2

ストリーミング ビデオ サーバーからの着信 jpeg フレームを処理する Delphi 6 Pro アプリケーションがあります。コードは機能しますが、最近、時間の経過とともに膨大な数のソフト ページ フォールトが生成されることに気付きました。いくつかの調査を行った後、ページ フォールトは 1 つの特定のグラフィック操作から発生しているように見えます。問題の圧縮されていないビットマップのサイズは 320 x 240 または約 300 KB であるため、大きな画像を処理するためではないことに注意してください。生成されるページ フォールトの数は許容範囲ではありません。1 時間で 1000000 ページ フォールトを簡単に超える可能性があります。

以下に含まれるコードをタイマーで 1 秒間に 10 回実行する、簡素化されたテスト ケースを作成しました。GetBitmap() メソッドで TJpegImage を TBitmap に割り当てようとすると、ページ フォールトが発生するようです。その行をコメントアウトしたため、ページ違反は発生しません。assign() は、圧縮解除されたビットを、GetBitmap() が返す新しく作成されたビットマップにプッシュするときに、TJpegImage の部分で圧縮解除操作をトリガーします。Microsoft の pfmon ユーティリティ (ページ フォールト モニター) を実行すると、RtlFillMemoryUlong に関する膨大な数のソフト ページ フォールト エラー行が表示されるため、メモリ バッファー フィル操作中に発生したように見えます。

1 つの不可解なメモ。どの DLL がどのページ フォールトを引き起こしたかを示す pfmon のレポートの要約部分では、左端の列に 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;

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

ありがとう、ロバート

4

1 に答える 1

0

割り当てて解放した割り当ては、メモリマネージャーによってリサイクルされないようです。

fastmm を使用するか、それらをプールして自分でリサイクルしてください。

于 2010-03-21T16:26:04.803 に答える