这是一个非常基本的问题.我将使用C和
Java来制定它,但它确实与语言无关.
考虑C中一个众所周知的问题:
考虑C中一个众所周知的问题:
struct Obj { boost::shared_ptr<Obj> m_field; }; { boost::shared_ptr<Obj> obj1(new Obj); boost::shared_ptr<Obj> obj2(new Obj); obj1->m_field = obj2; obj2->m_field = obj1; }
这是一个内存泄漏,大家都知道:)解决方案也是众所周知的:应该使用弱指针来打破“引用联盟”.还知道这个问题原则上不能自动解决.解决这个问题的程序员是唯一的责任.
但是有一个积极的事情:程序员完全控制了refcount值.我可以在调试器中暂停我的程序,并检查obj1,obj2的引用,并了解有一个问题.我还可以在对象的析构函数中设置断点,并观察破坏时刻(或者发现该对象未被销毁).
我的问题是关于Java,C#,ActionScript和其他“垃圾回收”语言.我可能会错过一些东西,但在我看来他们是
不要让我检查物体的计数
>对象被破坏时,不要让我知道(当对象暴露于GC时可以)
我经常听到这些语言不允许程序员泄漏记忆,这就是为什么他们是伟大的.据我所知,他们只是隐藏内存管理问题,难以解决.
最后,问题本身:
Java的:
public class Obj { public Obj m_field; } { Obj obj1 = new Obj(); Obj obj2 = new Obj(); obj1.m_field = obj2; obj2.m_field = obj1; }
>是内存泄漏吗?
>如果是,我如何检测并修复它?
>如果否:为什么?
解决方法
托管内存系统是建立在您不想首先跟踪内存泄漏问题的假设的基础上的.不要让它们更容易解决,您可以尝试确保它们始终不会发生.
Java确实有一个“内存泄漏”的缺点,这意味着内存的任何增长可能会影响到你的应用程序,但从来没有一点,托管内存不能清理所有的内存.
JVM不使用引用计数的原因有很多
>如您所观察到的,它不能处理循环引用.
它具有显着的内存和线程开销以保持准确.
>管理内存处理这种情况有更好,更简单的方法.
尽管JLS不禁止使用引用计数,但它并不用于任何JVM AFAIK.
相反,Java跟踪一些根上下文(例如每个线程堆栈),并且可以根据这些对象是否可以很强地跟踪哪些对象需要保留,哪些可以被丢弃.它还提供弱引用的设施(只要对象没有被清除就保留)和软引用(通常不会被清理,但可以在垃圾收集器处理)