简体   繁体   English

将TJpegImage分配给TBitmap时出现大量软页面错误

[英]Large number of soft page faults when assigning a TJpegImage to a TBitmap

I have a Delphi 6 Pro application that processes incoming jpeg frames from a streaming video server. 我有一个Delphi 6 Pro应用程序,该应用程序处理来自流视频服务器的传入jpeg帧。 The code works but I recently noticed that it generates a huge number of soft page faults over time. 该代码有效,但是我最近注意到,随着时间的推移,它会产生大量的软页面错误。 After doing some investigation, the page faults appear to be coming from one particular graphics operation. 经过一番调查后,页面错误似乎是由一个特定的图形操作引起的。 Note, the uncompressed bitmaps in question are 320 x 240 or about 300 KB in size so it's not due to the handling of large images. 请注意,未压缩的位图大小为320 x 240或大约300 KB,因此不是由于处理大图像而引起的。 The number of page faults being generated isn't tolerable. 不能产生的页面错误数。 Over an hour it can easily top 1000000 page faults. 在一个小时内,它可以轻松解决1000000个页面错误。

I created a stripped down test case that executes the code I have included below on a timer, 10 times a second. 我创建了一个精简的测试用例,它在计时器上执行我下面包含的代码,每秒执行10次。 The page faults appear to happen when I try to assign the TJpegImage to a TBitmap in the GetBitmap() method. 当我尝试在GetBitmap()方法中将TJpegImage分配给TBitmap时,似乎发生页面错误。 I know this because I commented out that line and the page faults do not occur. 我知道这一点是因为我注释掉了该行,并且不会发生页面错误。 The assign() triggers a decompression operation on the part of TJpegImage as it pushes the decompressed bits into a newly created bitmap that GetBitmap() returns. 当Assign()将解压缩的位压入GetBitmap()返回的新创建的位图时,它会触发TJpegImage的解压缩操作。 When I run Microsoft's pfmon utility (page fault monitor), I get a huge number of soft page fault error lines concerning RtlFillMemoryUlong, so it appears to happen during a memory buffer fill operation. 当我运行Microsoft的pfmon实用程序(页面错误监视器)时,我收到大量与RtlFillMemoryUlong有关的软页面错误错误行,因此它似乎发生在内存缓冲区填充操作期间。

One puzzling note. 一个令人费解的笔记。 The summary part of pfmon's report where it shows which DLL caused what page fault does not show any DLL names in the far left column. pfmon报告的摘要部分,其中显示哪个DLL导致了页面错误,但最左边的列中未显示任何DLL名称。 I tried this on another system and it happens there too. 我在另一个系统上尝试过,它也在那里发生。

Can anyone suggest a fix or a workaround? 谁能建议修复或解决方法? Here's the code. 这是代码。 Note, IReceiveBufferForClientSocket is a simple class object that holds bytes in an accumulating buffer. 注意,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;

// ---------------------------------------------------------------

Thanks, Robert 谢谢罗伯特

Sounds like the allocations that you allocate and free are not recycled by the memory manager. 听起来您分配和释放的分配不会被内存管理器回收。

Use fastmm, or better, pool them and recycle them yourself. 请使用fastmm,或者更好的方法是将它们合并起来并自己回收。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM