我有一个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;
// ---------------------------------------------------------------
谢谢,
罗伯特