gpt4 book ai didi

delphi - 在 FreeAndNil 之后使用对象时会发生什么?

转载 作者:行者123 更新时间:2023-12-03 14:44:38 25 4
gpt4 key购买 nike

在我的 Delphi7 中这段代码

var MStr: TMemoryStream;
...
FreeAndNil(MStr);
MStr.Size:=0;

生成 AV:模块“Project1.exe”中地址 0041D6D1 处的访问冲突。读取地址 00000000。但有人坚持认为,无论如何都不应该提出任何异常(exception)。他还说他的 Delphi 5 确实没有异常(exception)。他称之为“陈旧指针错误”。换句话说,他说 FreeAndNil 不能用作调试器来检测释放对象或使用已释放对象的双重尝试。

有人可以启发我吗?是否应该引发错误(总是/随机),或者程序应该毫无问题地运行此错误?

谢谢

<小时/>

我问这个是因为我相信我的程序中有“双重释放对象”或“释放并重新访问”错误。释放对象后,如何用零填充分配给对象的内存?我希望通过获取 AV 的方式来检测 bug 的位置。最初,我希望如果我将对象设置为 FreeAndNil,当我尝试重新访问它时,我总是会得到一个 AV。

最佳答案

使用空引用的方法或属性总是错误的,即使它有时看起来有效。

FreeAndNil 确实不能用于检测双重释放。对已经为 nil 的变量调用 FreeAndNil 是安全的。由于它是安全的,因此它不会帮助您检测任何内容。

这不是陈旧指针错误。这是一个空引用错误。陈旧指针错误是指您释放了一个对象,但没有清除引用该对象的所有变量。那么该变量仍然保存着对象的旧地址。这些很难被发现。你可能会遇到这样的错误:

MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;

您还可以得到这样的一个:

MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;

在释放引用的对象 MStr 后使用 MStr.Size 是一个错误,它应该引发异常。它是否确实引发异常取决于实现。也许会,也许不会。但这不是随机的。

如果您正在寻找双重释放错误,您可以使用 FastMM 提供的调试助手,正如其他人所建议的那样。它的工作原理是实际上并不将内存释放回操作系统,甚至不释放回 Delphi 的内部空闲内存池。相反,它将已知的错误数据写入对象的内存空间,因此当您看到这些值时,您就会知道您正在读取已经释放的内容。它还修改对象的 VMT,以便下次在该对象引用上调用虚拟方法时,您将得到一个可预测的异常,它甚至会告诉您尝试使用哪个所谓的已释放对象。当您尝试再次释放该对象时,它不仅可以告诉您已经释放了它,还可以告诉您第一次释放它的位置(带有堆栈跟踪)以及它被分配的位置。它还收集该信息来报告内存泄漏,即您释放对象少于一次而不是多次。

您还可以使用一些习惯来避免将来的代码出现问题:

  • 减少全局变量的使用。全局变量可以被整个程序中的任何代码修改,迫使您在使用它时想知道“这个变量的值仍然有效,还是其他代码已经释放了它?”当您限制变量的范围时,您可以减少程序中查找变量不具有预期值的原因时必须考虑的代码量。
  • 明确谁拥有某个对象。当有两段代码可以访问同一个对象时,您需要知道哪一段代码拥有该对象。它们可能都有一个不同的变量来引用该对象,但那里仍然只有一个对象。如果一段代码对其变量调用FreeAndNil,则另一代码的变量仍然保持不变。如果其他代码认为它拥有该对象,那么您就有麻烦了。 (所有者的概念不一定与 TComponent.Owner 属性相关联。不需要有一个对象拥有它;它可以是你的程序。)
  • 不要保留对不属于您的对象的持久引用。如果您不保留对对象的长期引用,那么您不必担心这些引用是否仍然有效。唯一的持久引用应该位于拥有该对象的代码中。任何其他需要使用该对象的代码都应该接收一个引用作为输入参数,使用该对象,然后在返回结果时丢弃该引用。

关于delphi - 在 FreeAndNil 之后使用对象时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/364184/

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