在FreeAndNil之后使用对象时应该会发生什么? [英] What's supposed to happen when using an object after FreeAndNil?

查看:108
本文介绍了在FreeAndNil之后使用对象时应该会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Delphi7中,这段代码

In my Delphi7 this code

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

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

generates an AV: Access violation at address 0041D6D1 in module 'Project1.exe'. Read of address 00000000. But somebody insists that it should not raise any exception, no matter what. He also says that his Delphi 5 indeed raises no exceptions. He calls this a "stale pointer bug". In other words he says that FreeAndNil cannot be used as debugger to detect a double attempt to free an object or to use a freed object.

有人可以启发我吗?这个提升和错误(总是/随机的)还是程序应该运行这个bug没有问题?

Can anybody enlighten me? Should this raise and error (always/randomly) or the program should run over this bug without problems?

谢谢

我问这个是因为我相信我有我的程序中的双重自由对象或自由和重新访问错误。在我释放对象之后,如何使用零填充分配给对象的内存?我想通过这种方式来检测错误在哪里,通过获取和AV。
最初,我希望如果我将对象设置为FreeAndNil,那么当我尝试重新访问它时,我将永远得到一个AV。

I ask this because I believe I have a "double free object" or "free and re-access" bug in my program. How can I fill the memory allocated to an object with zeros AFTER I freed the object? I want this way to detect where the bug is, by getting and AV. Initially, I hoped that if I set the object to FreeAndNil, I will ALWAYS get an AV when trying to re-access it.

推荐答案

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

It's always wrong to use methods or properties of a null reference, even if it appears to work sometimes.

FreeAndNil 实际上不能用于检测双重释放。在已经为零的变量上调用 FreeAndNil 是安全的。因为它是安全的,它不会帮助你检测到任何东西。

FreeAndNil indeed cannot be used to detect double frees. It is safe to call FreeAndNil on an already-nil variable. Since it's safe, it doesn't help you detect anything.

这不是一个陈旧的指针错误。这是一个空参考错误。一个陈旧的指针错误是当你释放一个对象,但是清除引用它的所有变量。那么变量仍然保存对象的旧地址。那些很难发现。你可以得到这样的错误:

This is not a stale-pointer bug. This is a null-reference bug. A stale-pointer bug is when you have freed an object but not cleared all variables that referenced it. Then the variable still holds the old address of the object. Those are very hard to detect. You can get such a bug like this:

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

您还可以得到如下一个:

You can also get one like this:

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

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

Using MStr.Size after you have freed the object MStr referenced is an error, and it should raise an exception. Whether it does raise an exception depends on the implementation. Maybe it will, and maybe it won't. It's not random, though.

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

If you're searching for a double-free bug, you can use the debugging aides that FastMM provides, as others have suggested as well. It works by not actually releasing the memory back to the operating system, or even back to Delphi's internal free-memory pool. Instead, it writes known-bad data into the object's memory space, so when you see those values, you'll know you're reading from something that you already freed. It also modifies the object's VMT so that the next time you call a virtual method on that object reference, you'll get a predictable exception, and it will even tell you which supposedly freed object you tried to use. When you attempt to free the object again, it can tell you not only that you already freed it, but also where it was freed the first time (with a stack trace), and where it was allocated. It also collects that information to report about memory leaks, where you freed an object less than one time instead of more.

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

There are also habits you can use to avoid the issue for future code:


  • 减少使用全局变量。整个程序中的任何代码都可以修改一个全局变量,迫使您在使用它时想知道,该变量的值是否仍然有效,还是已经有其他代码已经被释放了?当您限制变量的范围时,您可以减少程序中必须考虑的代码量,同时查找变量没有您期望的值的原因。

  • 清除关于谁拥有一个对象。当有两段代码可以访问同一个对象时,您需要知道哪些代码拥有该对象。他们可能每个都有一个不同的变量来引用对象,但是还有一个对象。如果一段代码在其变量上调用 FreeAndNil ,那么仍然保持其他代码的变量不变。如果其他代码认为它拥有该对象,那么您就遇到了麻烦。 (这个所有者的概念不一定与 TComponent.Owner 属性绑定,不需要是拥有它的对象;它可以是程序的通用子系统。)

  • 不要持久引用不拥有的对象。如果您不保留对对象的长期引用,那么您不必担心这些引用是否仍然有效。唯一的持久引用应该在拥有该对象的代码中。需要使用该对象的任何其他代码都应该接收引用作为输入参数,使用该对象,然后在返回其结果时丢弃引用。

  • Reduce the use of global variables. A global variable could be modified by any code throughout the program, forcing you to wonder whenever you use it, "Is this variable's value still valid, or did some other code free it already?" When you limit the scope of a variable, you reduce the amount of code you have to consider in your program when looking for reasons a variable doesn't have the value you expect.
  • Be clear about who owns an object. When there are two pieces of code that have access to the same object, you need to know which of those pieces of code owns the object. They might each have a different variable for referencing the object, but there's still just one object there. If one piece of code calls FreeAndNil on its variable, that still leave's the other code's variable unchanged. If that other code thinks it owns the object, then you're in trouble. (This concept of owner is not necessarily tied to the TComponent.Owner property. There doesn't need to be an object that owns it; it could be a general subsystem of your program.)
  • Don't keep persistent references to objects you don't own. If you don't keep long-lived references to an object, then you don't have to worry about whether those references are still valid. The only persistent reference should be in the code that owns the object. Any other code that needs to use that object should receive a reference as an input parameter, use the object, and then discard the reference when it returns its result.

这篇关于在FreeAndNil之后使用对象时应该会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆