我正在尝试解决 System.Classes.pas 中已知的丑陋性能限制,它具有 1980 年代的恒定缓冲区限制 ($F000),如下所示:
function TStream.CopyFrom(const Source: TStream; Count: Int64): Int64;
const
MaxBufSize = $F000;
....
这对我们的 Delphi 应用程序造成了严重的性能损失。在 delphi XE2 到 XE5 中,我们能够对此进行修改并使用以下方法之一:
我可以修改 Delphi 源代码,然后通过从批处理文件调用 dcc32.exe,在 Delphi 库文件夹中重建 System.Classes.dcu 文件。我意识到这很丑陋,我不喜欢这样做,但我也不喜欢 RTL 中这种丑陋的性能问题,而且我们的用户无法忍受它引起的性能问题。
我可以尝试将修改后的 system.classes.pas 文件放在我的项目搜索路径中的某个位置。
现在,上述方法在 Delphi XE6 中都不适合我,这可能要归功于一些内部编译器的更改。我在使用子句中包含 System.Contnrs 的最小命令行应用程序中遇到的错误是:
[dcc32 Fatal Error] System.Classes.pas(19600): F2051 Unit System.Contnrs was compiled with a different version of System.Classes.TComponent
重现此问题的示例程序(假设您已修改 System.Classes.pas 并更改了 MaxBufSize 常量),如下所示:
program consoletestproject;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Contnrs,
System.SysUtils;
var
List:System.Contnrs.TObjectList;
begin
WriteLn('Hello world');
end.
同样,这个问题在 Delphi XE6 中很容易重现,但在 XE5 或更早版本中不是问题。
当您绝对必须使用 System.Classes.pas 或 System.SysUtils.pas 或其他一些非常低级别的单元的修改副本来解决基本 RTL 或 VCL 限制时,建议的做法是什么? (是的,我知道如果没有必要,你不应该这样做,不要费心去听讲座。)
是否有一组神奇的命令行参数可以通过命令行上的“dcc32.exe”使用,以生成可以与上面的应用程序示例正确链接的修改后的 DCU?
作为第二个问题,是否存在没有源存在的 .dcu 文件,当尝试执行此操作时会中断,在这种情况下,上述所有问题的答案是,“您无法修复此问题,并且如果RTL 中存在错误,你运气不好”?
一种可能的解决方法是在项目搜索路径(或库路径)中包含“$(BDS)\source\rtl\common”,强制每个损坏的(需要重新编译)DCU 每次都进行重建,但这看起来很难看并且错了。
最佳答案
您可以通过迂回方式克服此限制,尝试使用 Delphi Detours Library
的示例
首先定义要 Hook 的方法的签名
var
Trampoline_TStreamCopyFrom : function (Self : TStream;const Source: TStream; Count: Int64): Int64 = nil;
然后实现绕行
function Detour_TStreamCopyFrom(Self : TStream;const Source: TStream; Count: Int64): Int64;
const
MaxBufSize = 1024*1024; //use 1 mb now :)
var
BufSize, N: Integer;
Buffer: TBytes;
begin
if Count <= 0 then
begin
Source.Position := 0;
Count := Source.Size;
end;
Result := Count;
if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count;
SetLength(Buffer, BufSize);
try
while Count <> 0 do
begin
if Count > BufSize then N := BufSize else N := Count;
Source.ReadBuffer(Buffer, N);
Self.WriteBuffer(Buffer, N);
Dec(Count, N);
end;
finally
SetLength(Buffer, 0);
end;
end;
最后用trampoline替换原来的函数(可以在某些单元的初始化部分使用这段代码)
Trampoline_TStreamCopyFrom := InterceptCreate(@TStream.CopyFrom, @Detour_TStreamCopyFrom);
要释放钩子(Hook),您可以使用
if Assigned(Trampoline_TStreamCopyFrom) then
InterceptRemove(@Trampoline_TStreamCopyFrom);
关于delphi - 我可以修改RTL类System.Classes.TStream中的常量并在Delphi XE6运行时重建它吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24145214/