如何判断对象指针所指向的堆内存是否已经释放

chenyq2008 2008-12-24 04:25:57

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TA = class
private
Fs: string;
public
constructor Create(s: string);
destructor Destroy;override;
procedure test;
end;


TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
A: TA;
begin
A := TA.Create('test');
A.Free;
//A := nil;
//if A <> nil then
if Assigned(A) then
A.test;
end;

{ TA }

constructor TA.Create(s: string);
begin
Fs:= s;
end;

destructor TA.Destroy;
begin
Fs:= '';
inherited;
end;

procedure TA.test;
begin
ShowMessage(Fs);
end;

end.


例如以上代码,A对象所指向的堆内存已经free了,但无论判断A是否为nil或者用assigned判断,都可以调用A.test而不出错。应该怎么判断A已经Free而不至于执行A.test呢?
...全文
450 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
chijingde 2008-12-26
  • 打赏
  • 举报
回复
万年不回贴

一回贴就丢个大人

不懂装懂真是害人啊

MLGBD
JPEXE 2008-12-25
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 chenyq2008 的回复:]
To JPEXE:
你只是在特定的类中做标记,我是想问在普通的类应用中有没可能做判断
[/Quote]
要在你的"普通应用"中做到,感觉好难啊,等待高手吧,帮顶.
sdzeng 2008-12-25
  • 打赏
  • 举报
回复
没什么好办法,主要还得靠程序员养成良好习惯

按理说,内存使用情况,操作系统是最清楚的,但是操作系统一般不会具备这种机制
因此java和.net才要在虚拟机上搞内存回收
chenyq2008 2008-12-25
  • 打赏
  • 举报
回复
To JPEXE:
你只是在特定的类中做标记,我是想问在普通的类应用中有没可能做判断
chijingde 2008-12-25
  • 打赏
  • 举报
回复
楼上说的对

忘了这玩意是个类方法了
ZuoBaoquan 2008-12-25
  • 打赏
  • 举报
回复
@chijingde

InstanceSize是类方法(class function),其隐含的Self指针实际上指向的是某个具体的Class。
所以无论a释放与否,结果都是一样。

ZuoBaoquan 2008-12-25
  • 打赏
  • 举报
回复
@JPEXE
这样实现是不行的。
ZuoBaoquan 2008-12-25
  • 打赏
  • 举报
回复
无论一个对象有几个引用,只有有一个调用了Free,这个对象所在内存的空间就被“毁”了。所以像使用flag等实例字段根本没有作用。

其实根本的重点不在于判断对象指针所指向的堆内存是否已经释放,而是某个对象是不是应该有多个引用。

根据领域驱动设计的思想,有些对象只能通过它的聚合根来访问。这样不仅能减少对象引用,还可以让程序更容易理解和维护。如果有很多地方需要使用这个对象,是不是应该抽象出一个接口,然后由其自己(接口的引用计数)管理引用?
chijingde 2008-12-25
  • 打赏
  • 举报
回复
TA=class
i:integer;
end;
chijingde 2008-12-25
  • 打赏
  • 举报
回复
InstanceSize 返回类对象占据的内存大小

var a:TA;
begin
a:=TA.Create;
A.i:=100;
ShowMessage(IntToStr(a.InstanceSize));
a.Free;
ShowMessage(IntToStr(a.InstanceSize));
end;
JPEXE 2008-12-24
  • 打赏
  • 举报
回复
再完善了一下代码,下面的代码应该能印证楼主的需求:"因为程序中对一个对象的引用变量可能不止一个,当对一个对象的引用变量FreeAndNil后,有可能忘记将另外的引用变量为nil,所以有可能出现我所问的问题"

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
{ 用这个类实现标记/判断对象是否已被释放 }
TCheckIsAlive = class
private
flag: Boolean; { 类创建时成员变量 flag 一定会被初始化为 False }
function GetIsAlive: Boolean;
public
destructor Destroy; override;
property IsAlive: Boolean read GetIsAlive;
end;

TA = class(TCheckIsAlive) { 注意继承 }
private
Fs: string;
public
constructor Create(s: string);
destructor Destroy; override;
procedure test;
end;

TForm1 = class(TForm)
btn1: TButton;
btn2: TButton;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
private
FA: TA;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
A: TA;
begin
A := TA.Create('test'); { 创建 }
FA := A; { 引用 }

{ 检查是否 alive }
if A.IsAlive then
A.test; { 未释放->会执行 }

A.Free; { 释放 }
end;

procedure TForm1.btn2Click(Sender: TObject);
begin
{ 检查是否 alive }
if FA.IsAlive then
FA.test; { 已被释放->不会执行 }
end;

{ TA }

constructor TA.Create(s: string);
begin
Fs := s;
end;

destructor TA.Destroy;
begin
Fs := '';
inherited;
end;

procedure TA.test;
begin
ShowMessage(Fs);
end;

{ TCheckIsAlive }

destructor TCheckIsAlive.Destroy;
begin
flag := True; { 修改标记 }
end;

function TCheckIsAlive.GetIsAlive: Boolean;
begin
Result := not flag;
end;

end.
myy 2008-12-24
  • 打赏
  • 举报
回复
简单说,没有办法做到。
JPEXE 2008-12-24
  • 打赏
  • 举报
回复
有句注释写错了
{ TCheckIsFree } 应该是 { TCheckIsAlive }
JPEXE 2008-12-24
  • 打赏
  • 举报
回复
不知道这样能不能满足你的要求.
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
{ 用这个类实现标记/判断对象是否已被释放 }
TCheckIsAlive = class
private
flag: Boolean; { 类创建时成员变量 flag 一定会被初始化为 False }
function GetIsAlive: Boolean;
public
destructor Destroy; override;
property IsAlive: Boolean read GetIsAlive;
end;

TA = class(TCheckIsAlive) { 注意继承 }
private
Fs: string;
public
constructor Create(s: string);
destructor Destroy; override;
procedure test;
end;

TForm1 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
A: TA;
begin
A := TA.Create('test');
A.Free;

{ 检查是否 alive }
if A.IsAlive then
A.test;
end;

{ TA }

constructor TA.Create(s: string);
begin
Fs := s;
end;

destructor TA.Destroy;
begin
Fs := '';
inherited;
end;

procedure TA.test;
begin
ShowMessage(Fs);
end;

{ TCheckIsFree }

destructor TCheckIsAlive.Destroy;
begin
flag := True; { 修改标记 }
end;

function TCheckIsAlive.GetIsAlive: Boolean;
begin
Result := not flag;
end;

end.

不需改变对TA类的使用,只需让TA从TCheckIsAlive继承就行了.
rcaicc 2008-12-24
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 chenyq2008 的回复:]
引用 7 楼 JPEXE 的回复:
我的目的就是想在A不为nil的情况下如何判断堆内存是否已释放
/Quote]

A不为NIL的时候还有可能被释放了吗?
chenyq2008 2008-12-24
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 JPEXE 的回复:]
引用 4 楼 chenyq2008 的回复:
引用 3 楼 JPEXE 的回复:
//A := nil;
//if A <> nil then

正确的做法就应该是这样啊,为什么要注释掉.

Free以后立即赋值为nil,为以后使用前判断提供依据.
我的目的就是想在A不为nil的情况下如何判断堆内存是否已释放

是否可以说说你更深层的目的是什么?
或者说说你遇到了什么样的情况非要这样判断,而不能在free后赋值nil(因为这才是推荐的编码方法).
[/Quote]因为程序中对一个对象的引用变量可能不止一个,当对一个对象的引用变量FreeAndNil后,有可能忘记将另外的引用变量为nil,所以有可能出现我所问的问题
liangpei2008 2008-12-24
  • 打赏
  • 举报
回复
可能需要参考一些检测内存泄露的代码!
JPEXE 2008-12-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 chenyq2008 的回复:]
引用 3 楼 JPEXE 的回复:
//A := nil;
//if A <> nil then

正确的做法就应该是这样啊,为什么要注释掉.

Free以后立即赋值为nil,为以后使用前判断提供依据.
我的目的就是想在A不为nil的情况下如何判断堆内存是否已释放
[/Quote]
是否可以说说你更深层的目的是什么?
或者说说你遇到了什么样的情况非要这样判断,而不能在free后赋值nil(因为这才是推荐的编码方法).
huangjacky 2008-12-24
  • 打赏
  • 举报
回复
有想法.好青年.
帮顶
JPEXE 2008-12-24
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 huangjacky 的回复:]
所以free的时候 你用freeandnil吧.
不然貌似delphi里面还真的不能判断.
[/Quote]
对,顶2楼,也可以直接用FreeAndNil(...)方法.
var
A: TA;
begin
A := TA.Create('test');
FreeAndNil(A); {和A.Free; A:=nil;是一个效果}
if Assigned(A) then
A.test; {这句将不会被执行了}
end;
加载更多回复(4)

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧