gpt4 book ai didi

delphi - 低内存占用,适用于不同数据类型的大型阵列

转载 作者:行者123 更新时间:2023-12-03 19:48:03 24 4
gpt4 key购买 nike

使用大型阵列时,我需要节省物理内存。在当前的代码版本中,我为每个数据类型定义了一个这样的类

TMyData_01 = class 
Const ID=$0001;
public
Data : Integer;
end;

TMyData_02 = class
Const ID=$0002;
public
Data : String;
end;
TMyData_03 = class
Const ID=$0003;
public
Data : TDateTime;
Index : Integer;
end;
TMyData_04 = class
Const ID=$0004;
public
Data : TDateTime;
Value : Real;
end;
...


我有〜50种不同的基本类别类型,以及这些类别的一些组合。

   MyCombinedData = class 
Const ID=$0002;
public
Data_1 : TMyData_01;
Data_2 : TMyData_02;
Data_3 : TMyData_03;
Data_4 : TMyData_04;
end;


在当前的代码版本中,我可以将数据读取和写入这些许多类类型,并将所有这些类的列表作为项目运行在列表/数组中。

但是现在我遇到了内存不足的问题,因为我的方法无效
因为每种类类型都消耗16字节的访问空间+数据本身的其他字节。

此外,如果在组合类中,并非所有子类都填充有数据
我使用此静态方法创建了许多未有效使用的内存空间。


MyCombinedData [1]的数据位于子类1,2,3中
MyCombinedData [2]的数据位于子类2,3中
MyCombinedData [3]具有子类1,2,3,4中的数据
MyCombinedData [4]的数据位于子类2、3、4中
.....


在Delphi中,有没有更好的方法来存储具有较低内存占用量的不同数据?

最佳答案

您可以执行以下操作(如果较低的内存使用量比代码简单性更重要):

const
MaxBufferSize = 16; // the largest size you actually need, in this example sizeof(TMyData_04)...

type
TMyData = packed record
TypeID: Byte;
Buffer: array[0..MaxBufferSize-1] of Byte;
end;

PMyData_01 = ^TMyData_01;
TMyData_01 = packed record
Data: Integer;
end;

PMyData_02 = ^TMyData_02;
TMyData_02 = packed record
Data: String;
end;

PMyData_03 = ^TMyData_03;
TMyData_03 = packed record
Data: TDateTime;
Index: Integer;
end;

PMyData_04 = ^TMyData_04;
TMyData_04 = packed record
Data: TDateTime;
Value: Real;
end;

...


然后,您可以将 TMyData实例数组分配给所需的长度,并调用 System.Initialize()初始化包含编译器管理的数据类型的所有项目:

var
Arr: array of TMyData;

SetLength(Arr, ...);

//...

Arr[Index].TypeID := $01;
System.Initialize(PMyData_01(@Arr[Index].Buffer)^);
// populate PMyData_01(@Arr[Index].Buffer)^ fields as needed...

// and so on ...


不要忘记在取消分配数组之前在项目上调用 System.Finalize(),以避免任何内存泄漏:

var
I: Integer;
begin
for I := Low(Arr) to High(Arr) do
begin
case Arr[I].TypeID of
$01: System.Finalize(PMyData_01(@Arr[i].Buffer)^);
$02: System.Finalize(PMyData_02(@Arr[i].Buffer)^);
$03: System.Finalize(PMyData_03(@Arr[i].Buffer)^);
$04: System.Finalize(PMyData_04(@Arr[i].Buffer)^);
// and so on ...
end;
end;
end;


不太理想,但是可以使用...



通过一些泛型技巧,您可以稍微清理一下代码:

const
MaxBufferSize = 16; // the largest size you actually need, in this example sizeof(TMyData_04)...

type
TMyDataHelper<T: record> = record
type PtrType = ^T;
class function GetDataTypeID: Byte; static;
end;

TMyData = packed record
TypeID: Byte;
Buffer: array[0..MaxBufferSize-1] of Byte;
procedure InitializeBuffer<T: record>;
procedure FinalizeBuffer;
procedure SetBufferData<T: record>(const NewData: T);
function BufferAs<T: record>: TMyDataHelper<T>.PtrType;
end;

TMyData_01 = packed record
Data: Integer;
end;

TMyData_02 = packed record
Data: String;
end;

TMyData_03 = packed record
Data: TDateTime;
Index: Integer;
end;

TMyData_04 = packed record
Data: TDateTime;
Value: Real;
end;

// and so on ...

class function TMyDataHelper<T>.GetDataTypeID: Byte;
begin
if TypeInfo(T) = TypeInfo(TMyData_01) then
Result := $01
else
if TypeInfo(T) = TypeInfo(TMyData_02) then
Result := $02
else
if TypeInfo(T) = TypeInfo(TMyData_03) then
Result := $03
else
if TypeInfo(T) = TypeInfo(TMyData_04) then
Result := $04
// and so on ...
else
Result := $00;
end;

procedure TMyData.InitializeBuffer<T>;
var
LTypeID: Byte;
begin
LTypeID := TMyDataHelper<T>.GetDataTypeID;
if TypeID <> LTypeID then
begin
FinalizeBuffer;
System.Initialize(BufferAs<T>^);
TypeID := LTypeID;
end;
end;

procedure TMyData.FinalizeBuffer;
begin
case TypeID of
$01: Finalize(BufferAs<TMyData_01>^);
$02: Finalize(BufferAs<TMyData_02>^);
$03: Finalize(BufferAs<TMyData_03>^);
$04: Finalize(BufferAs<TMyData_04>^);
// and so on ...
else
FillChar(Buffer, SizeOf(Buffer), $00);
end;
end;

procedure TMyData.SetBufferData<T>(const NewData: T);
begin
InitializeBuffer<T>;
BufferAs<T>^ := NewData;
end;

function TMyData.BufferAs<T>: TMyDataHelper<T>.PtrType;
begin
Result := TMyDataHelper<T>.PtrType(@Buffer);
end;




var
Arr: array of TMyData;

SetLength(Arr, ...);
FillChar(Arr[0], Length(Arr)*SizeOf(TMyData), $0);

//...

Arr[Index].InitializeBuffer<TMyData_01>;
populate Arr[Index].BufferAs<TMyData_01>^ fields as needed...
or:
Arr[Index].SetBufferData<TMyData_01>(...);

// and so on ...




var
I: Integer;
begin
for I := Low(Arr) to High(Arr) do
Arr[I].FinalizeBuffer;
end;

关于delphi - 低内存占用,适用于不同数据类型的大型阵列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46352524/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com