我的同事讲那天你如何能在Delphi中,如果你真的把事情搞得一团糟泄漏的字符串。 默认情况下,字符串是引用计数和自动分配的,所以他们通常只是没有任何的思想工作 - 无需手动配置,尺寸计算,或内存管理。
不过,看完记得曾经有直接泄漏的字符串(不包括其在被泄露的对象)的方式。 现在看来似乎有一些东西需要用引用传递一个字符串,然后从它被传递到程序中,从更大范围内访问它。 是的,我知道这是模糊的,这就是为什么我在这里问这个问题。
我的同事讲那天你如何能在Delphi中,如果你真的把事情搞得一团糟泄漏的字符串。 默认情况下,字符串是引用计数和自动分配的,所以他们通常只是没有任何的思想工作 - 无需手动配置,尺寸计算,或内存管理。
不过,看完记得曾经有直接泄漏的字符串(不包括其在被泄露的对象)的方式。 现在看来似乎有一些东西需要用引用传递一个字符串,然后从它被传递到程序中,从更大范围内访问它。 是的,我知道这是模糊的,这就是为什么我在这里问这个问题。
事实上,经过串为const或非const的是在引用计数项相同的德尔福2007年和2009年曾经有一个字符串为const传递是导致访问冲突的情况下。 这里是一个问题
type
TFoo = class
S: string;
procedure Foo(const S1: string);
end;
procedure TFoo.Foo(const S1: string);
begin
S:= S1; //access violation
end;
var
F: TFoo;
begin
F:= TFoo.create;
try
F.S := 'S';
F.Foo(F.S);
finally
F.Free;
end;
end.
我不知道在你的第二段的问题,但我被记录泄露串咬一次。
如果您在包含字符串的记录调用FillChar()您覆盖裁判计数和使用零动态分配的内存地址。 除非该字符串为空,这将泄漏内存。 解决这个问题的办法是清除它占用的内存之前调用的Finalize()上的记录。
不幸的是调用的Finalize()时,有需要最后确定没有记录部件会导致编译器提示。 它发生在我身上,我注释掉最后确定()调用沉默暗示,但后来当我添加了一个字符串成员我错过了在取消对通话记录,引入这样的泄漏。 幸运的是,我通常用在调试模式下最详细和偏执设定FastMM内存管理器,所以泄漏并没有被忽视。
编译器提示可能不是这样的好事,默默省略最后确定(),如果它是没有必要的会好得多恕我直言称。
不,我不认为这样的事情会发生。 这是可能的一个字符串变量来获得你没想到的值,但它不会泄漏内存。 试想一下:
var
Global: string;
procedure One(const Arg: string);
begin
Global := '';
// Oops. This is an invalid reference now. Arg points to
// what Global used to refer to, which isn't there anymore.
writeln(Arg);
end;
procedure Two;
begin
Global := 'foo';
UniqueString(Global);
One(Global);
Assert(Global = 'foo', 'Uh-oh. The argument isn''t really const?');
end;
这里One
的参数声明为const,所以推测,它不会改变。 但随后One
规避,通过改变实际参数代替形式参数。 步骤Two
“知道” One
“的说法是常量,所以预计实际参数保留其原始值。 断言失败。
串并没有泄露,但是这个代码不演示了如何得到一个字符串悬挂参考 。 Arg
是一个本地别名Global
。 虽然我们已经改变了Global
, Arg
的价值保持不变,因为它被声明为const,该字符串的引用计数并没有在进入功能增加。 重新分配Global
下跌的引用计数为零,该字符串被摧毁。 声明Arg
为VAR将有同样的问题; 按值传递,将解决这个问题。 (所述的呼叫UniqueString
只是以确保字符串是引用计数否则,它可能是一个非参考计数字符串文字。)所有编译器管理的类型是容易受到此问题; 简单类型有免疫力。
泄漏字符串的唯一方法是把它当作字符串以外的东西,或者使用非感知类型的内存管理功能。 Mghie的回答说明了如何将一个字符串通过使用字符串以外的东西FillChar
给揍一个字符串变量。 无感知类型的内存功能包括GetMem
和FreeMem
。 例如:
type
PRec = ^TRec;
TRec = record
field: string;
end;
var
Rec: PRec;
begin
GetMem(Rec, SizeOf(Rec^));
// Oops. Rec^ is uninitialized. This assignment isn't safe.
Rec^.field := IntToStr(4);
// Even if the assignment were OK, FreeMem would leak the string.
FreeMem(Rec);
end;
有两种方法来解决它。 一个是调用Initialize
并Finalize
:
GetMem(Rec, SizeOf(Rec^));
Initialize(Rec^);
Rec^.field := IntToStr(4);
Finalize(Rec^);
FreeMem(Rec);
另一种是使用类型感知功能:
New(Rec);
Rec^.field := IntToStr(4);
Dispose(Rec);
我想这可能是类似我在想什么的。 这是一个字符串泄漏,那被收集早期字符串的反向:
var
p : ^String;
procedure InitString;
var
s, x : String;
begin
s := 'A cool string!';
x := s + '. Append something to make a copy in' +
'memory and generate a new string.';
p := @x;
end;
begin
{ Call a function that will generate a string }
InitString();
{ Write the value of the string (pointed to by p) }
WriteLn(p^); // Runtime error 105!
{ Wait for a key press }
ReadLn;
end.
泄漏的字符串的另一种方法是将其声明为线程变量。 见我的问题的详细信息。 而对于解决方案,看看如何把它打扫干净的解决方案 。