本文主要是介绍\t\tHook TStream类的copyfrom,大大提高效率,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Hook TStream类的copyfrom,大大提高效率
此文原创,转载请注明出处
作者:二娃
之前关于这遍博文的内容我曾发表在盒子论坛内,现在利用这段时间好好写下来,以备大家一起来来研究,
我在用Remobjects做服务端项目时,发现Remobject服务端代码有一个执行的瓶颈,它用到很多TStream类的copyfrom这个成员函数,这个Copyfrom在整个客户端挤占了1/3的耗时.打个比方,
copyfrom工作原理是申请一块最大为$F000内存空间,从源stream内读一块内容到这块内存空间上,目标stream再写入这块内存上的内容到自身的内容,然后销毁这块内存,如此反复,直到源stream读被读完,这对于两个stream都是如filestream一样非含有本身的内存存储stream是有好处的,我想borland在写copyfrom这个函数时是基于这个考虑的,但是这种方法会大大降低代码的效率,原因就出在不停地申请缓冲区内存。
再仔细研究了Remobject用到copyfrom的地方,发现与之对应的两个stream至少一个是继承自TCustomMemoryStream,由于就联想到能否用TCustomMemoryStream代替父类TStream来操作copyfrom,这是因为TCustomMemoryStream有个属性叫memory,这是一个指针,指向实际该stream的内容,只要是能到内容的指针,在地址上的内容访问就变得很简单,
本来我想写一个继承自TMemoryStream的stream类,重写copyfrom方法,但是发现在TStream的copyfrom的成员函数后面没有virturl,abstract,连override都没有,所以写这个方法的覆盖就要用到reintroduce,但是这样也麻烦,因为我不能为每个第三方代码内的stream重写copyfrom方法,
还好在这里cnpack的zjy等大侠提供了一个TCnMethodhook的类(关于地址的hook请参阅其它的网上文章,这里不作讨论),那剩下事只要我将copyfrom写好,然后去hook TStream类的copyfrom,这样,只要我项目中用到stream的copyfrom地方,我就不用改动任何第三方代码的源码就能达到目的,
以下内容为 hook copyfrom的单元,直接此用到单元下就ok,目前在若干项目中测试过,能将remobject的用到copyfrom的地方的耗时降低的不计的程度
//代码开始
unit uCnFastStream;
interface
implementation
uses
Classes,CnMethodHook;
type
TStreamCopyFromFun= function(Slf:TStream; Source: TStream; Count: Int64): Int64;
var
_CnStreamCopyFromHook:TCnMethodHook;
_OldStreamCopyFromFun:TStreamCopyFromFun;
function CnFastStreamCopyFrom(Slf, Source: TStream; Count: Int64): Int64;
var
aRealSize:Int64;
aSlfStream:TCustomMemoryStream absolute Slf;
aSourceStream:TCustomMemoryStream absolute Source;
begin
if Count = 0 then
begin
Source.Position := 0;
Count := Source.Size;
end;
Result:=Count;
//注意此方法能工作的首要条件是Slf, Source两者之一是TCustomMemoryStream,否则调用原函数
//判断Slf或Source是不是TCustomMemoryStream,如果是的话,直接从Memory的地址上进行操作 ,
//因为CustomMemoryStream 的read或writer都用到System.move
//这样省去了原TStream不停地创建和写buffer 及设置Capacity ,原copyfrom这里最浪费时间
//用此方法可直接将Source的内存块追加到Slf的Memory地址的后面
aRealSize:=Source.Size-Source.Position;
if Result>aRealSize then
Result:=aRealSize;
//如果没有数据需要与入,就退出
if Result=0 then
Exit;
if (Slf is TCustomMemoryStream)
then
begin
//先设置内存的大小,将slf.Memory扩大,不然下面找不到地址
Slf.Size:=Slf.Position+Result;
//source直接从slf.memory后面写
Result:=Source.Read(Pointer(Longint(aSlfStream.Memory) + Slf.Position)^,Result);
Slf.Position:=Slf.Position+Result; //将Slf Position推后
Slf.Size:=Slf.Position;
end
else
//如果没有Memory 则可能有另外的处理方式, 如果TADOBlobStream
if (Source is TCustomMemoryStream) and Assigned(aSourceStream.Memory)
then
begin
//直接写入到Slf的地址内
Result:=Slf.Write(Pointer(Longint(aSourceStream.Memory) + Source.Position)^,Result);
Source.Position:=Source.Position+Result; //将Source Position推后
end
else
begin
//如果两者皆不是,用原有的copyfrom进行处理
_CnStreamCopyFromHook.UnhookMethod;
try
Result:=_OldStreamCopyFromFun(Slf,Source,Result);
finally
_CnStreamCopyFromHook.HookMethod;
end;
end;
end;
initialization
_OldStreamCopyFromFun:=CnGetBplMethodAddress(@TStream.CopyFrom);
_CnStreamCopyFromHook:=TCnMethodHook.Create(@_OldStreamCopyFromFun,@CnFastStreamCopyFrom);
finalization
_CnStreamCopyFromHook.Free;
_CnStreamCopyFromHook:=nil;
end.
//代码结束
这篇关于\t\tHook TStream类的copyfrom,大大提高效率的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!