代码之家  ›  专栏  ›  技术社区  ›  Robert Oschler Rob

将TJPEG图像分配给TbitMap时出现大量软页面错误

  •  2
  • Robert Oschler Rob  · 技术社区  · 15 年前

    我有一个Delphi6 Pro应用程序,它处理来自流媒体视频服务器的传入JPEG帧。代码可以工作,但我最近注意到,随着时间的推移,它会生成大量的软页面错误。在做了一些调查之后,页面错误似乎来自一个特定的图形操作。注意,所讨论的未压缩位图大小为320 x 240或大约300 KB,因此这不是由于处理大型图像所致。生成的页面错误数是不可容忍的。一个小时后,它可以轻松地超过1000000个页面错误。

    我创建了一个精简的测试用例,它以每秒10次的速度在计时器上执行下面包含的代码。当我试图在getBitmap()方法中将TJPEG图像分配给Tbitmap时,页面错误似乎会发生。我之所以知道这一点,是因为我注释掉了那一行,并且没有出现页面错误。assign()在将解压缩的位推入getBitmap()返回的新创建位图时,触发对TJPEG图像部分的解压缩操作。当我运行微软的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;
    
    // ---------------------------------------------------------------
    

    谢谢, 罗伯特

    1 回复  |  直到 15 年前
        1
  •  0
  •   Marco van de Voort    15 年前

    听起来像是您分配和释放的分配不会被内存管理器回收。

    使用fastmm,或者更好,把它们放在一起自己回收。