下面是一个非常简单的代码,它模仿我的一些代码中的类结构(表单只包含一个附加到click事件的单个按钮)。我正在使用Delphi XE和XE II,并在销毁此类所基于的生产代码中的对象时看到令人讨厌的崩溃。仅当我允许在Clear()方法中初始化TMyClass中的数组项的成员时,才会发生这些崩溃。
不幸的是,到目前为止,在此示例代码中崩溃是不可重复的,但它确实模仿了一些非常奇怪的行为,我怀疑这可能是导致问题的原因。
如果我在TMyClass.Clear函数中放置一个断点并查看类报告1288的InstanceSize成员。这很奇怪,因为单独的数组成员的大小实际上是12kb。我可以将从TRecord2提供的类型更改为Integer,并获得相同的InstanceSize结果。如果我从类中完全删除数组,我得到的实例大小约为264字节,对于只包含一个128字节记录实例的类来说,这似乎超过了顶层。这表明编译器已为TMyClass中的V(TT类型)成员的数组存储分配了1024个字节。
我怀疑当我将12kb数据写入编译器认为大小为1kb的对象时,奇怪的实例大小会导致不良事件发生。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TRecord = record A : Array[1..128] of byte; end;
TRecord2 = packed record S : Single; T : TDateTime; end;
TBase = class(TObject)
public
R : TRecord;
end;
TBase2<T> = class(TBase)
public
type
TT = packed array [0..31, 0..31] of T;
var
V : TT;
R2 : TRecord;
end;
TMyClass = class(TBase2<TRecord2>)
public
procedure Clear;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
O : TMyClass;
begin
O := TMyClass.Create;
O.Clear;
O.Free;
end;
{ TMyClass }
procedure TMyClass.Clear;
var
i, j : integer;
begin
for i := 0 to 31 do
for j := 0 to 31 do
begin
V[I, J].S := 0;
V[I, J].T := 0;
end;
end;
end.
答案 0 :(得分:8)
这是一个错误,正如这个最小的再现所示:
program InstanceSizeBug;
{$APPTYPE CONSOLE}
type
TMyClass<T> = class
V: array [0..255] of T;
end;
TMyClassSingle = class(TMyClass<Single>);
begin
Writeln(TMyClass<Single>.InstanceSize);
Writeln(TMyClassSingle.InstanceSize);
Readln;
end.
输出:
1032
264
请注意,在Delphi 2010中可以观察到相同的行为,这是我必须提供的唯一其他Delphi版本。
在调试器下跟踪,你发现自己在_GetMem
中,Size
参数等于264
,所以显然没有分配足够的内存。
如果有任何疑问,这个版本会失败,AV。
program InstanceSizeBug;
{$APPTYPE CONSOLE}
type
TMyClass<T> = class
V: array [1..256*256] of T;
end;
TMyClassSingle = class(TMyClass<Single>);
begin
TMyClassSingle.Create.V[256*256] := 0;
end.
我已向Quality Central提交此问题,问题#100561。
作为一种解决方法,我建议您使用在构造函数中使用SetLength分配的动态数组。我更倾向于想象存在一个固定大小的通用数组会使编译器行为不端。