垃圾收集与手动内存管理

Nic*_*ick 9 c++ java jvm memory-leaks memory-management

这是一个非常基本的问题.我将使用C++和Java来表达它,但它确实与语言无关.考虑一下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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个内存泄漏,每个人都知道:).解决方案也是众所周知的:应该使用弱指针来打破"refcount interlocking".还已知原则上不能自动解决该问题.解决它只是程序员的责任.

但是有一个积极的事情:程序员可以完全控制refcount值.我可以在调试器中暂停我的程序并检查obj1,obj2的引用计数并理解存在问题.我还可以在对象的析构函数中设置断点并观察破坏时刻(或找出该对象尚未被破坏).

我的问题是Java,C#,ActionScript和其他"垃圾收集"语言.我可能会遗漏一些东西,但在我看来他们

  1. 不要让我检查对象的引用计数
  2. 当对象被破坏时不要让我知道(好吧,当对象暴露给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;
}
Run Code Online (Sandbox Code Playgroud)
  1. 是内存泄漏吗?
  2. 如果是:我如何检测并修复它?
  3. 如果不是:为什么?

Pet*_*rey 8

托管内存系统建立在您不希望首先跟踪内存泄漏问题的假设之上.而不是让它们更容易解决,你试着确保它们永远不会发生在一起.

Java确实有一个"内存泄漏"的丢失术语,这意味着内存中的任何增长可能会影响您的应用程序,但是管理内存无法清除所有内存.

出于多种原因,JVM不使用引用计数

  • 你已经观察到它无法处理循环引用.
  • 它具有显着的内存和线程开销,可以准确维护.
  • 有更好,更简单的方法来处理托管内存的这种情况.

虽然JLS不禁止使用引用计数,但它并未在任何JVM AFAIK中使用.

相反,Java会跟踪许多根上下文(例如,每个线程堆栈),并且可以跟踪哪些对象需要保留,哪些可以根据这些对象是否可以高度访问而被丢弃.它还为弱引用提供了工具(只要对象没有被清理就会被保留)和软引用(通常不会被清理但可以由垃圾收集者自行决定)


Rei*_*ica 5

AFAIK,Java GC的工作原理是从一组明确定义的初始引用开始,并计算可以从这些引用中获得的对象的传递闭包.任何无法访问的内容都是"泄露"的,可以进行GC编辑.