java - 垃圾收集与手动内存管理

标签 java c++ memory-management memory-leaks jvm

这是一个非常基本的问题。我将使用 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;
}

这是内存泄漏,每个人都知道 :)。解决方案也是众所周知的:应该使用弱指针来打破“引用计数互锁”。众所周知,这个问题原则上不能自动解决。解决它完全是程序员的责任。

但有一件好事:程序员可以完全控制引用计数值。我可以在调试器中暂停我的程序并检查 obj1、obj2 的 refcount 并了解存在问题。我还可以在对象的析构函数中设置断点并观察销毁时刻(或发现对象尚未被销毁)。

我的问题是关于 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;
}
  1. 是内存泄漏吗?
  2. 如果是:如何检测和修复它?
  3. 如果不是:为什么?

最佳答案

托管内存系统是建立在您不希望首先跟踪内存泄漏问题的假设之上的。与其让它们更容易解决,不如从一开始就确保它们永远不会发生。

Java 确实有一个“内存泄漏”的术语,这意味着任何可能影响您的应用程序的内存增长,但从来没有一点托管内存无法清理所有内存。

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

  • 如您所见,它无法处理循环引用。
  • 需要大量内存和线程开销才能准确维护。
  • 有更好、更简单的方法来处理托管内存的此类情况。

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

相反,Java 会跟踪一些根上下文(例如每个线程堆栈),并且可以根据这些对象是否强可达来跟踪哪些对象需要保留,哪些可以丢弃。它还为弱引用(只要对象未清理就保留)和软引用(通常不清理但可由垃圾收集器自行决定)提供便利

关于java - 垃圾收集与手动内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16315959/

相关文章:

Java:想要对数组的子集进行二进制搜索

java - org.apache.wicket.util.resource.IResourceStream引发JavaScript错误。不能下载文件

java - 将 JAXB 注释应用于现有数据模型

c++ - __(两个下划线)在 Hpux C 程序中代表什么

Perl:什么时候释放不需要的标量内存而不超出范围?

java - Java/Android 中对现有对象的短期引用的开销

javascript - 如何确保所有HTML均已加载

c++ - 如何替换标准 multimap 中的 <key, value>

c++ - fork() 输出链

javascript - 什么是DOM js内存容量?