gpt4 book ai didi

delphi - 如何确定动态数组的引用数量?

转载 作者:行者123 更新时间:2023-12-02 01:44:08 25 4
gpt4 key购买 nike

根据这个问题( Dynamic arrays and memory management in Delphi ),如果我在 Delphi 中创建动态数组,如何访问引用计数?

SetLength(a1, 100);
a2 := a1;
// The reference count for the array pointed to by both
// a1 and a2 should be 2. How do I retrieve this?

另外,如果引用计数可以访问的话,是否也可以手动修改呢?后一个问题主要是理论性的,而不是实际使用的(与上面的第一个问题不同)。

最佳答案

您可以通过检查System单元中的代码来了解如何管理引用计数。以下是 XE3 源代码中的相关部分:

type
PDynArrayRec = ^TDynArrayRec;
TDynArrayRec = packed record
{$IFDEF CPUX64}
_Padding: LongInt; // Make 16 byte align for payload..
{$ENDIF}
RefCnt: LongInt;
Length: NativeInt;
end;
....
procedure _DynArrayAddRef(P: Pointer);
begin
if P <> nil then
AtomicIncrement(PDynArrayRec(PByte(P) - SizeOf(TDynArrayRec))^.RefCnt);
end;

function _DynArrayRelease(P: Pointer): LongInt;
begin
Result := AtomicDecrement(PDynArrayRec(PByte(P) - SizeOf(TDynArrayRec))^.RefCnt);
end;

动态数组变量保存一个指针。如果数组为空,则指针为 nil。否则,指针包含数组第一个元素的地址。在数组的第一个元素之前存储数组的元数据。 TDynArrayRec 类型描述了该元数据。

因此,如果您希望读取引用计数,您可以使用与 RTL 完全相同的技术。例如:

function DynArrayRefCount(P: Pointer): LongInt;
begin
if P <> nil then
Result := PDynArrayRec(PByte(P) - SizeOf(TDynArrayRec))^.RefCnt
else
Result := 0;
end;

如果您想修改引用计数,则可以通过公开System中的函数来实现:

procedure DynArrayAddRef(P: Pointer);
asm
JMP System.@DynArrayAddRef
end;

function DynArrayRelease(P: Pointer): LongInt;
asm
JMP System.@DynArrayRelease
end;

请注意,RTL 设计者选择的名称 DynArrayRelease 有点误导,因为它只是减少了引用计数。当计数达到零时,它不会释放内存。

请注意,我不确定您为什么要这样做。请记住,一旦开始修改引用计数,您就必须对其正确性承担全部责任。例如,这个程序泄漏:

{$APPTYPE CONSOLE}

var
a, b: array of Integer;

type
PDynArrayRec = ^TDynArrayRec;
TDynArrayRec = packed record
{$IFDEF CPUX64}
_Padding: LongInt; // Make 16 byte align for payload..
{$ENDIF}
RefCnt: LongInt;
Length: NativeInt;
end;

function DynArrayRefCount(P: Pointer): LongInt;
begin
if P <> nil then
Result := PDynArrayRec(PByte(P) - SizeOf(TDynArrayRec))^.RefCnt
else
Result := 0;
end;

procedure DynArrayAddRef(P: Pointer);
asm
JMP System.@DynArrayAddRef
end;

function DynArrayRelease(P: Pointer): LongInt;
asm
JMP System.@DynArrayRelease
end;

begin
ReportMemoryLeaksOnShutdown := True;
SetLength(a, 1);
Writeln(DynArrayRefCount(a));
b := a;
Writeln(DynArrayRefCount(a));
DynArrayAddRef(a);
Writeln(DynArrayRefCount(a));
a := nil;
Writeln(DynArrayRefCount(b));
b := nil;
Writeln(DynArrayRefCount(b));
end.

如果您调用 DynArrayRelease 将引用计数归零,那么出于上面讨论的原因,您还需要处置该数组。我从未遇到过需要操作引用计数的问题,强烈建议您避免这样做。

最后一点。 RTL 不通过其公共(public)接口(interface)提供此功能。这意味着以上所有内容都是私有(private)实现细节。因此在未来的版本中可能会发生变化。如果您确实尝试读取或修改引用计数,那么您必须认识到这样做依赖于此类实现细节。

关于delphi - 如何确定动态数组的引用数量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22163259/

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