我有一个Delphi 6 Pro应用程序,可以处理来自流媒体视频服务器的传入jpeg帧。代码有效,但我最近注意到它会随着时间的推移产生大量的软页面错误。在进行一些调查之后,页面错误似乎来自一个特定的图形操作。请注意,所讨论的未压缩位图的大小为320 x 240或大约300 KB,因此不是由于处理大图像。生成的页面错误数是不可容忍的。超过一个小时,它可以很容易地超过1000000页错误。
我创建了一个精简测试用例,它在计时器上执行下面包含的代码,每秒10次。当我尝试在GetBitmap()方法中将TJpegImage分配给TBitmap时,会出现页面错误。我知道这是因为我注释掉了这一行并且没有发生页面错误。 assign()在TJpegImage部分触发解压缩操作,因为它将解压缩的位推送到GetBitmap()返回的新创建的位图中。当我运行Microsoft的pfmon实用程序(页面错误监视器)时,我收到大量关于RtlFillMemoryUlong的软页面错误错误行,因此它似乎发生在内存缓冲区填充操作期间。
令人费解的一个问题。 pfmon报告的摘要部分,其中显示哪个DLL导致哪个页面错误未在最左列显示任何DLL名称。我在另一个系统上尝试了这个,它也发生在那里。
有人可以建议修复或解决方法吗?这是代码。注意,IReceiveBufferForClientSocket是一个简单的类对象,它在一个累积缓冲区中保存字节。
function GetBitmap(theJpegImage: TJpegImage): Graphics.TBitmap;
begin
Result := TBitmap.Create;
Result.Assign(theJpegImage);
end;
// ---------------------------------------------------------------
procedure processJpegFrame(intfReceiveBuffer: IReceiveBufferForClientSocket);
var
theBitmap: TBitmap;
theJpegStream, theBitmapStream: TMemoryStream;
theJpegImage: TJpegImage;
begin
theBitmap := nil;
theJpegImage := TJPEGImage.Create;
theJpegStream:= TMemoryStream.Create;
theBitmapStream := TMemoryStream.Create;
try // 2
// ************************ BEGIN JPEG FRAME PROCESSING
// Load the JPEG image from the receive buffer.
theJpegStream.Size := intfReceiveBuffer.numBytesInBuffer;
Move(intfReceiveBuffer.bufPtr^, theJpegStream.Memory^, intfReceiveBuffer.numBytesInBuffer);
theJpegImage.LoadFromStream(theJpegStream);
// Convert to bitmap.
theBitmap := GetBitmap(theJpegImage);
finally
// Free memory objects.
if Assigned(theBitmap) then
theBitmap.Free;
if Assigned(theJpegImage) then
theJpegImage.Free;
if Assigned(theBitmapStream) then
theBitmapStream.Free;
if Assigned(theJpegStream) then
theJpegStream.Free;
end; // try()
end;
// ---------------------------------------------------------------
procedure TForm1.Timer1Timer(Sender: TObject);
begin
processJpegFrame(FIntfReceiveBufferForClientSocket);
end;
// ---------------------------------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
var
S: string;
begin
FIntfReceiveBufferForClientSocket := TReceiveBufferForClientSocket.Create(1000000);
S := loadStringFromFile('c:\test.jpg');
FIntfReceiveBufferForClientSocket.assign(S);
end;
// ---------------------------------------------------------------
谢谢, 罗伯特
答案 0 :(得分:0)
听起来你分配和免费的分配不会被内存管理器回收。
使用fastmm或更好的方法将它们集中并自行回收。