String Delphi字符串内存泄漏?
我有一个程序,它接受SQL查询作为命令行参数,查询PostgreSQL数据库并生成一个以多种方式之一格式化的文件(通常用于生成CSV文件) 然而,这个程序有严重的内存泄漏——对于一个生成12MB文件的特定查询,在操作系统杀死它之前,程序使用8GB的RAM加上几GB的交换空间。我想找出内存泄漏的原因。我不太了解Delphi(从程序的质量来看,原作者也不太了解),但我的任务是找到一个快速修复方法 以下String Delphi字符串内存泄漏?,string,delphi,memory-leaks,copy,String,Delphi,Memory Leaks,Copy,我有一个程序,它接受SQL查询作为命令行参数,查询PostgreSQL数据库并生成一个以多种方式之一格式化的文件(通常用于生成CSV文件) 然而,这个程序有严重的内存泄漏——对于一个生成12MB文件的特定查询,在操作系统杀死它之前,程序使用8GB的RAM加上几GB的交换空间。我想找出内存泄漏的原因。我不太了解Delphi(从程序的质量来看,原作者也不太了解),但我的任务是找到一个快速修复方法 以下doData函数部分输出结果集的一行。我猜问题出在“copy”命令(在堆上创建一个永远不会释放的字符
doData
函数部分输出结果集的一行。我猜问题出在“copy”命令(在堆上创建一个永远不会释放的字符串)上,但我相信比我更有经验的人能够确认这个答案或为我指明正确的方向
procedure doData;
var
s, fldVal : string;
i, fldLen : integer;
begin
s := '';
for i := 0 to ds.Fields.Count-1 do
begin
if (ds.Fields[i].DataType = ftDate) or
(ds.Fields[i].DataType = ftDateTime) then
begin
if psql.outDate = 'i' then
fldLen := 8
else
fldLen := 10;
if ds.Fields[i].IsNull then
fldVal := ''
else
fldVal := formatDate(ds.Fields[i].AsDateTime);
end
else
begin
fldLen := ds.Fields[i].DisplayWidth;
fldVal := ds.Fields[i].AsString;
end;
if (psql.outType = 'd') or (psql.outType = 's') then
s := s + trim(fldVal)
else if psql.outType = 'f' then
begin
s := s + fldVal;
if fldLen - length(fldVal) > 0 then
s := s + copy(spaces, 1, fldLen - length(fldVal));
// Is this a memory leak above?
end;
if psql.outType = 's' then
begin
if i < ds.Fields.Count-1 then
s := s + psql.outDelimChar;
end
else
s := s + psql.outDelimChar;
end;
writeln(psql.outPrefixData + s);
end;
程序数据;
变量
s、 fldVal:字符串;
i、 fldLen:整数;
开始
s:='';
对于i:=0到ds.Fields.Count-1 do
开始
如果(ds.Fields[i].DataType=ftDate)或
(ds.Fields[i].DataType=ftDateTime)然后
开始
如果psql.outDate='i',则
弗德伦:=8
其他的
fldLen:=10;
如果ds.Fields[i].为空,则
fldVal:=''
其他的
fldVal:=formatDate(ds.Fields[i].AsDateTime);
结束
其他的
开始
fldLen:=ds.Fields[i].DisplayWidth;
fldVal:=ds.Fields[i].AsString;
结束;
如果(psql.outType='d')或(psql.outType='s'),则
s:=s+微调(fldVal)
否则,如果psql.outType='f',则
开始
s:=s+fldVal;
如果fldLen-长度(fldVal)>0,则
s:=s+copy(空格,1,fldLen-长度(fldVal));
//这是上面的内存泄漏吗?
结束;
如果psql.outType='s',则
开始
如果i
此代码中没有泄漏。Delphistring
类型由编译器管理,不需要程序员显式释放内存
如果希望查找泄漏,则应包括的完整调试版本。这将生成代码中任何泄漏的诊断报告,包括帮助确定泄漏内存最初分配位置的堆栈跟踪。此代码中没有泄漏。Delphi
string
类型由编译器管理,不需要程序员显式释放内存
如果希望查找泄漏,则应包括的完整调试版本。这将生成代码中任何泄漏的诊断报告,包括帮助识别泄漏内存最初分配位置的堆栈跟踪。Delphi字符串类型使用引用计数进行管理。当字符串变量超出范围时,它将自动销毁。
Copy
无法在此代码中创建内存泄漏。如果生成的是12MB字符串,则说明您做错了:请改用TStringBuilder(或直接写入流)。但是使用像s:=s+xx
这样的代码对内存处理非常不利我发现mad是识别内存泄漏的有效工具,但是从你的代码片段开始,我可能会检查ds
和psql
被释放的位置-你可能会很幸运…我以前只需在某些位置放置断点,并在任务管理器中观察内存使用量的增加,就可以诊断出严重的内存泄漏。(请注意,可能需要一秒钟的时间才能显示,Delphi内存管理器不会立即释放回操作系统,等等,这可能会使它变得复杂。)但在内存管理器只会上升且每次增量都很大的情况下,通常很容易找到导致它的代码段。然后你把它缩小到一个函数、函数的一部分和一行。另外,我猜不是字符串(如LU RD所解释的),而是对象引用保存得太长——也就是说,没有尽早释放它们。我的猜测是数据库查询中数据的副本,即程序只是将所有内容都保存在内存中,而不是对每个字段执行任何操作,并在迭代到下一个字段之前释放该数据。不过这只是一个猜测。我在上面的代码中看不到任何明显的东西。根据我上面的评论缩小范围。Delphi字符串类型使用引用计数进行管理。当字符串变量超出范围时,它将自动销毁。Copy
无法在此代码中创建内存泄漏。如果生成的是12MB字符串,则说明您做错了:请改用TStringBuilder(或直接写入流)。但是使用像s:=s+xx
这样的代码对内存处理非常不利我发现mad是识别内存泄漏的有效工具,但是从你的代码片段开始,我可能会检查ds
和psql
被释放的位置-你可能会很幸运…我以前只需在某些位置放置断点,并在任务管理器中观察内存使用量的增加,就可以诊断出严重的内存泄漏。(请注意,可能需要一秒钟的时间才能显示,Delphi内存管理器不会立即释放回操作系统,等等,这可能会使它变得复杂。)但在内存管理器只会上升且每次增量都很大的情况下,通常很容易找到导致它的代码段。然后你把它缩小到一个函数、函数的一部分和一行。另外,我猜不是字符串(如LU RD所解释的),而是对象引用保存得太长——也就是说,没有尽早释放它们。我猜应该是数据库查询中数据的副本,即p