在我的Delphi7中这段代码
var MStr: TMemoryStream;
...
FreeAndNil(MStr);
MStr.Size:=0;
生成 AV:模块“Project1.exe”中地址 0041D6D1 处的访问冲突。读取地址 00000000。
但有人坚持认为,无论如何都不应该提出任何例外。他还说他的 Delphi 5 确实没有例外。他称之为“陈旧指针错误”。
换句话说,他说 FreeAndNil 不能用作调试器来检测释放对象或使用已释放对象的双重尝试。
有人可以启发我吗?是否应该引发错误(总是/随机),或者程序应该毫无问题地运行此错误?
Thanks
我问这个问题是因为我相信我的程序中有“双重释放对象”或“释放并重新访问”错误。释放对象后,如何用零填充分配给对象的内存?我希望通过获取 AV 的方式来检测 bug 的位置。
最初,我希望如果我将对象设置为 FreeAndNil,当我尝试重新访问它时,我总是会得到一个 AV。
使用空引用的方法或属性总是错误的,即使它有时看起来有效。
FreeAndNil
确实不能用于检测双重释放。打电话是安全的FreeAndNil
在一个已经为零的变量上。因为它是安全的,所以它不能帮助您检测任何东西。
这不是陈旧指针错误。这是一个空引用错误。陈旧指针错误是指当您释放了一个对象但not清除引用它的所有变量。那么该变量仍然保存着对象的旧地址。这些很难被发现。你可能会遇到这样的错误:
MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;
您还可以获得这样的一个:
MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;
Using MStr.Size
释放对象后MStr
引用是一个错误,它应该引发异常。无论does引发异常取决于实现。也许会,也许不会。但这不是随机的。
如果您正在寻找双重释放错误,您可以使用 FastMM 提供的调试助手,正如其他人所建议的那样。它的工作原理是实际上并不将内存释放回操作系统,甚至不释放回 Delphi 的内部空闲内存池。相反,它将已知的错误数据写入对象的内存空间,因此当您看到这些值时,您就会知道您正在读取已经释放的内容。它还修改对象的 VMT,以便下次在该对象引用上调用虚拟方法时,您将得到一个可预测的异常,它甚至会告诉您尝试使用哪个所谓的已释放对象。当您尝试再次释放该对象时,它不仅可以告诉您已经释放了它,还可以告诉您第一次释放它的位置(带有堆栈跟踪)以及它被分配的位置。它还收集该信息以报告内存泄漏(您在其中释放了对象)less不止一次而不是更多。
您还可以使用一些习惯来避免将来的代码出现问题:
- 减少全局变量的使用。全局变量可以被整个程序中的任何代码修改,迫使您在使用它时想知道“这个变量的值仍然有效,还是其他代码已经释放了它?”当您限制变量的范围时,您可以减少程序中查找变量不具有预期值的原因时必须考虑的代码量。
- 明确谁拥有某个对象。当有两段代码可以访问同一个对象时,您需要知道哪一段代码owns物体。它们可能都有一个不同的变量来引用该对象,但那里仍然只有一个对象。如果一段代码调用
FreeAndNil
在它的变量上,仍然保持其他代码的变量不变。如果其他代码认为它拥有该对象,那么您就有麻烦了。 (所有者的概念不一定与TComponent.Owner
财产。不需要有一个object拥有它的人;它可能是您程序的通用子系统。)
- 不要保留对不属于您的对象的持久引用。如果您不保留对对象的长期引用,那么您不必担心这些引用是否仍然有效。唯一的持久引用应该位于拥有该对象的代码中。任何其他需要使用该对象的代码都应该接收引用作为输入参数,使用该对象,然后在返回结果时丢弃该引用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)