Delphi 6 OleServer.pas调用内存泄漏

时间:2010-03-15 18:14:37

标签: delphi memory com invoke memory-leaks

在delphi 6中有一个错误,您可以在线找到一些参考资料,当您导入tlb时,事件调用中的参数顺序会被反转。它在导入的标题中反转一次,在TServerEventDIspatch.Invoke中反转一次。

您可以在此处找到有关它的更多信息: http://cc.embarcadero.com/Item/16496

在某种程度上与此问题有关,在TServerEventDispatch.Invoke中出现内存泄漏,其参数类型Var_Array的Variant(可能是其他的,但这是我能看到的更明显的一个)。调用代码将args复制到VarArray中以传递给事件处理程序,然后在调用之后将VarArray复制回args,相关代码粘贴在下面:

  // Set our array to appropriate length
  SetLength(VarArray, ParamCount);

  // Copy over data
  for I := Low(VarArray) to High(VarArray) do
    VarArray[I] := OleVariant(TDispParams(Params).rgvarg^[I]);

  // Invoke Server proxy class
  if FServer <> nil then FServer.InvokeEvent(DispID, VarArray);

  // Copy data back
  for I := Low(VarArray) to High(VarArray) do
    OleVariant(TDispParams(Params).rgvarg^[I]) := VarArray[I];

  // Clean array
  SetLength(VarArray, 0);

在我的案例中有一些明显的解决方法:如果我在VarArray参数的情况下跳过复制,它会修复泄漏。不改变功能,我认为我应该将数组中的数据而不是变量复制回params,但这可能会变得复杂,因为它可以容纳其他变体,在我看来需要递归完成。

由于OleServer的更改会产生连锁反应,我想确保我的更改严格正确。

任何人都可以了解为什么内存会泄露到这里?我似乎无法查询任何低于TServerEventDIspatch.Invoke的callstack(为什么会这样?)

我想在复制变量的过程中,将VarArray复制回参数列表,它添加了对数组的引用,因此不允许它像正常一样释放,但这只是一个粗略的猜测,我无法追踪支持它的代码。

也许对这一切有更好了解的人可以解释一下?

1 个答案:

答案 0 :(得分:2)

有趣的是,我认为解决方案是我在问题中提供的链接,但是直到深入了解它之后我才明白这个含义。

要澄清一些事项:

  1. 当从VarArray将包含数组的变体分配回Params时,会生成一个副本。这在delphi帮助页面中进行了解释。
  2. 分配现有变体肯定会释放与Variant的先前值相关联的内存,因此在分配之前变体包含的数组将在分配时释放。
  3. VarClear将释放与变体关联的内存,并且测试显示赋值后变量中的VarClear保留在Params中实际上会消除内存泄漏。
  4. 似乎问题与不加选择地回写参数值有关。我正在处理的特定事件没有任何标记为var的参数,因此COM对象不期望更改调用参数以释放已分配的新内存。

    大致COM对象分配了一个数组,调用该事件然后在事件发生后释放它自己的内存。然而,当Oleserver将数组参数复制回到COM对象甚至不知道的参数列表时,Oleserver会分配一些新内存,因为它没有通过引用传递任何内容,并且不期望更改其参数。那里必须有一些额外的编组魔法,我忽略了,如果有人知道细节,我肯定会好奇。

    TVariantArg的vt字段有一个标志,指示它是通过值还是引用传递。据我所知,如果param被标记为通过引用传递,我们应该只复制值。

    此外,可能有必要做的不仅仅是分配变量,如果这实际上是通过引用传递,虽然可以由编组处理,但仍然不确定这部分。

    现在的解决方案是将代码更改为:

    if ((TDispParams(Params).rgvarg^[I].vt and VT_BYREF) <> 0) then begin
      OleVariant(TDispParams(Params).rgvarg^[I]) := VarArray[I];
    end;