如何在Delphi中使用HeapCreate和HeapAlloc分配类?下面的示例将崩溃。
program Project2;
uses
System.SysUtils,
System.Classes,
Winapi.Windows;
var
SL: TStringList;
Handle: THandle;
P: ^TStringList;
begin
Handle := HeapCreate(0, SizeOf(TStringList), SizeOf(TStringList));
P := HeapAlloc(Handle, 0, SizeOf(TStringList));
P.Add('some random string'); // crash
HeapFree(Handle, 0, @P);
end.发布于 2015-11-05 21:19:23
Delphi只为从主内存管理器以外的任何地方分配对象提供了有限的便利。为此,您需要重写类的NewInstance方法。构造函数调用这个方法来分配类的一个新实例。破坏的对应物是FreeInstance。
重写这些方法并调用HeapAlloc和HeapFree。然而,SizeOf并没有给出要分配的字节数。SizeOf告诉您对象引用的大小,它总是SizeOf(Pointer)。您需要实例的大小,该实例由类的InstanceSize方法提供。
尽管可以重写使用所选内存分配策略的方法,但您可能不会对结果感到满意,因为有一些问题:
NewInstance方法不接受任何参数,因此您无法告诉类要从哪个堆分配。您可以有一个全局堆,或者每个类有一个堆,但是不能为每个实例单独选择要使用的堆。NewInstance方法,因此无法只分配特定堆上的某些实例,并从默认内存管理器分配其余的实例。这主要是前一个问题的另一种措辞方式。TMyStringList,但不能分配TStringList。(当然可以,但它需要修补每个类的VMT,这通常是不推荐的。)您尝试过的代码有一些问题。首先,您从未实际分配过一个TStringList。您为一个指针分配了一个指针,正如我前面提到的,它是SizeOf(Pointer)字节。这不足以容纳一个TStringList实例。
你根本就不需要^TStringList。可以将分配的内存直接分配给TStringList变量SL。
SL := HealAlloc(Handle, 0, TStringList.InstanceSize);注意我是怎么调整尺寸的。
但是,这仍然不够,因为虽然分配了一些内存,但它还没有构造对象。您需要调用构造函数。
SL.Create;注意,构造函数将分配更多的内存来保存字符串列表,并分配更多的内存来保存字符串内容。这些内存分配不会放在堆上。他们会去默认的内存管理器,就像往常一样。
摧毁这个物体将是另一个问题。您需要调用析构函数来释放字符串,但是如果这样做,析构函数也将尝试释放对象的内存。它将使用默认内存管理器来释放它,但是由于您没有使用默认内存管理器来分配TStringList对象,内存管理器将抛出一个EInvalidPointer异常。
Delphi无法在不释放相关内存的情况下销毁对象。也就是说,您不能在不调用FreeInstance的情况下调用FreeInstance,但是TStringList.FreeInstance将调用FreeMem而不是HeapFree。
我建议您从当前的任务后退一步,重新检查您想要解决的问题,并为特定对象创建一个单独的堆。也许会有更好的解决方案,不需要花费太多的精力来与工具的设计目标作斗争。
https://stackoverflow.com/questions/33554573
复制相似问题