7

在用 ToBytes 方法(见下文)将 AnsiString 的硬类型转换替换为 TBytes(字符串数组)后,Delphi 报告没有内存泄漏 - 但是,Free Pascal 2.6.2 显示泄漏,以防 TBytes 值传递给具有类型的参数Pointer

以下代码泄漏内存:

program project1;

{$mode delphi}

uses
  SysUtils;

function ToBytes(const AValue: AnsiString): TBytes;
begin
  SetLength(Result, Length(AValue)); // <-- leak (ine 10)
  if Length(AValue) > 0 then
    Move(AValue[1], Result[0], Length(AValue));
end;

procedure Send(P: Pointer);
begin

end;

begin
  Send(ToBytes('test'));

  SetHeapTraceOutput('heaptrace.log');
end. 

内存泄漏报告:

Call trace for block $001C5CC0 size 12   $00401586  TOBYTES,  line 10
of project1.lpr   $00401622  main,  line 21 of project1.lpr

如果我将 Send 方法更改为采用 TBytes 类型的参数,内存泄漏就会消失。

4

3 回答 3

4

那是一个编译器错误。托管类型TBytes具有引用计数的生命周期。编译器应该创建一个隐式局部变量,该变量分配给ToBytes. 您需要通过存储到显式本地来解决此问题:

var
  Tmp: TBytes;
....
Tmp := ToBytes(...);
Send(Tmp);
于 2014-03-04T19:44:23.327 回答
1

它可能不是您认为的错误。FPC 的堆跟踪已知在主程序(主 .dpr begin..end)中跟踪临时(和一般的自动类型)存在问题。

将代码移动到一个过程中,然后从 main 开始..end 调用它。你会看到泄漏消失了。

这是因为主程序的一般结构是这样的

begin 
  initializeunits(); // procedure call inserted by the compiler
    <actual mainprogram statements>
  finalizeunits();   // procedure call inserted by the compiler
end.

随着主程序临时的释放发生在“结束”。在完成堆跟踪的 finalizeunits 之后。(即使是第一个单元,它仍然只是一个单元)。所以 heaptrc 错过了这一点。

于 2014-03-05T13:38:07.233 回答
0

返回可能包含大量内存的东西的函数让我感到不安。这可能只是一种感觉或个人偏好,但它确实剥夺了对内存分配的控制权。关于返回(新构造的)TStringList 实例的函数也有类似的说法,建议将指针传递给 TStrings 对象并让调用者控制对象的生命周期。

在这里,我建议对 TBytes 上的所有操作使用 var 参数,并强制调用者提供一个实例来处理。如果您构建了一个复杂的应用程序并且必须搜索可以提高性能的地方,请再考虑一下,看看您是否可以回收类似内容或长度的 TBytes 实例。Delphi 字符串系统的一个重要特性是在幕后为您进行引用计数和写时复制,当您的应用程序处理大量(相似)字符串时提供这种性能增益。

于 2014-03-04T21:04:57.800 回答