\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.

//代码结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值