0

我想编写一些程序来帮助我在指向动态分配的地址空间的指针离开堆栈时自动释放内存。一个例子是:

procedure FillMemory (var mypointer);
begin
  // CopyMemory, Move, etc... with data
end;

procedure MyProcedure;
var
  MyPointer : Pointer;
begin
  MyPointer := VirtualAlloc (NIL, 1024, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  FillMemory (MyPointer);
  VirtualFree(MyPointer, 0, MEM_RELEASE); // I would like to avoid this...
end;

我可以使用字符串,但我也想避免使用它们(我不太确定堆栈中的字符串是否会被释放......)有什么想法吗?

4

2 回答 2

4

为了扩展我与 Arioch 的评论和讨论,

如果您只想要一个原始内存块,请使用动态array of byte. 编译器将生成代码以在方法结束时释放此内存:

type
  TBytes = array of Byte; // omit for newer Delphi versions

procedure FillMemory(var Bytes: TBytes);
begin
  { passing in here will increase the reference count to 2 }
  // CopyMemory, Move, etc... with data
end; // then drop back to 1

procedure MyProcedure;
var
  Buffer : TBytes;
begin
  SetLength(Buffer, 1024);  // buffer has reference count of 1
  FillMemory (Buffer);
end;   // reference count will drop to 0, and Delphi will free memory here

希望这一切都有意义。现在是午夜,所以我感觉不是最清醒的......

于 2013-07-15T12:02:02.833 回答
3

托管类型对其引用进行计数,当计数降至零时,它们将被最终确定。如果你有一个局部变量,那么当它超出范围时,它的引用计数将下降到零。

TInterfacedObject因此,您可以使用接口创建您引用的后代。像这样的东西:

type
  TLifetimeWatcher = class(TInterfacedObject)
  private
    FDestroyProc: TProc;
  public
    constructor Create(const DestroyProc: TProc);
    destructor Destroy; override;
  end;

constructor TLifetimeWatcher.Create(const DestroyProc: TProc);
begin
  inherited Create;
  FDestroyProc := DestroyProc;
end;

destructor TLifetimeWatcher.Destroy;
begin
  if Assigned(FDestroyProc) then
    FDestroyProc();
  inherited;
end;

然后你可以像这样使用它:

procedure MyProcedure;
var
  MyPointer: Pointer;
  LifetimeWatcher: IInterface;
begin
  MyPointer := VirtualAlloc (NIL, 1024, MEM_COMMIT or MEM_RESERVE, 
    PAGE_EXECUTE_READWRITE);
  LifetimeWatcher := TLifetimeWatcher.Create(
    procedure
    begin
      VirtualFree(MyPointer, 0, MEM_RELEASE);
    end;
  )
  FillMemory(MyPointer);
end;

LifetimeWatcher离开作用域时,实现对象被销毁并执行您传递给的过程TLifetimeWatcher.Create

将这个想法专门用于您的用例将很容易。这将使呼叫站点的代码更加简洁。

看起来像这样:

function VirtualAllocAutoRelease(Size: SIZE_T; Protect: DWORD;
  out LifetimeCookie: IInterface): Pointer;
var
  Ptr: Pointer;
begin
  Ptr := VirtualAlloc(nil, Size, MEM_COMMIT or MEM_RESERVE, Protect);
  Win32Check(Ptr<>nil);
  LifetimeCookie := TLifetimeWatcher.Create(
    procedure
    begin
      VirtualFree(Ptr, 0, MEM_RELEASE);
    end
  );
  Result := Ptr;
end;

你会像这样使用它:

procedure MyProcedure;
var
  MyPointer: Pointer;
  LifetimeWatcher: IInterface;
begin
  MyPointer := VirtualAllocAutoRelease(1024, PAGE_EXECUTE_READWRITE, 
    LifetimeWatcher);
  FillMemory(MyPointer);
end;
于 2013-07-15T11:29:45.460 回答