我一直在使用ZLib
函数来压缩/解压缩内存中的流。如果我尝试解压缩无效流,它会泄漏内存。以下代码会泄漏内存:
uses
Winapi.Windows, System.Classes, System.ZLib;
function DecompressStream(const AStream: TMemoryStream): Boolean;
var
ostream: TMemoryStream;
begin
ostream := TMemoryStream.Create;
try
AStream.Position := 0;
// ISSUE: Memory leak happening here
try
ZDecompressStream(AStream, ostream);
except
Exit(FALSE);
end;
AStream.Clear;
ostream.Position := 0;
AStream.CopyFrom(ostream, ostream.Size);
result := TRUE;
finally
ostream.Free;
end;
end;
var
s: TMemoryStream;
begin
ReportMemoryLeaksOnShutdown := TRUE;
s := TMemoryStream.Create;
try
DecompressStream(s);
finally
s.Free;
end;
end.
我尝试在这里解压缩空TMemoryStream
,并在执行结束时显示内存泄漏发生。在Delphi XE2上进行测试。
任何想法如何防止这种泄漏发生,因为在现实世界中我的应用程序有可能尝试解压缩无效流并泄漏内存。
QC:http://qc.embarcadero.com/wc/qcmain.aspx?d=120329 - 声称已从XE6开始修复
答案 0 :(得分:3)
这是Delphi RTL代码中的一个错误。 ZDecompressStream
的实现引发异常,然后无法执行整理。我们来看看代码:
procedure ZDecompressStream(inStream, outStream: TStream);
const
bufferSize = 32768;
var
zstream: TZStreamRec;
zresult: Integer;
inBuffer: TBytes;
outBuffer: TBytes;
inSize: Integer;
outSize: Integer;
begin
SetLength(inBuffer, BufferSize);
SetLength(outBuffer, BufferSize);
FillChar(zstream, SizeOf(TZStreamRec), 0);
ZCompressCheck(InflateInit(zstream)); <--- performs heap allocation
inSize := inStream.Read(inBuffer, bufferSize);
while inSize > 0 do
begin
zstream.next_in := @inBuffer[0];
zstream.avail_in := inSize;
repeat
zstream.next_out := @outBuffer[0];
zstream.avail_out := bufferSize;
ZCompressCheck(inflate(zstream, Z_NO_FLUSH));
// outSize := zstream.next_out - outBuffer;
outSize := bufferSize - zstream.avail_out;
outStream.Write(outBuffer, outSize);
until (zstream.avail_in = 0) and (zstream.avail_out > 0);
inSize := inStream.Read(inBuffer, bufferSize);
end;
repeat
zstream.next_out := @outBuffer[0];
zstream.avail_out := bufferSize;
zresult := ZCompressCheck(inflate(zstream, Z_FINISH));
// outSize := zstream.next_out - outBuffer;
outSize := bufferSize - zstream.avail_out;
outStream.Write(outBuffer, outSize);
until (zresult = Z_STREAM_END) and (zstream.avail_out > 0);
ZCompressCheck(inflateEnd(zstream)); <--- tidy up, frees heap allocation
end;
我从我的XE3中获取了这个,但我相信它在所有版本中基本相同。我突出了这个问题。对inflateInit
的调用会从堆中分配内存。它需要与inflateEnd
的调用配对。由于ZCompressCheck
会在出现错误时引发异常,因此对inflateEnd
的调用永远不会发生。因此代码泄漏。
使用try / finally正确保护该单元中对inflateInit
和inflateEnd
的其他调用。它似乎只是在这个函数中使用是错误的。
我的建议是将Zlib
单元替换为正确实现的版本。