Java - 何时卸载此对象?

时间:2011-10-07 22:49:43

标签: java garbage-collection linked-list

这是我的代码:

    LinkedList <Mono> list = new LinkedList ();

    list.add(new Mono (2, 2));
    list.add(new Mono (1, -1));
    list.remove (1);

现在,当删除列表中的第二项时,对象是否已被销毁? IE,它经历了垃圾收集?

9 个答案:

答案 0 :(得分:4)

新问题

编辑

是的,当没有强引用时,该对象将有资格进行垃圾回收。但是JVM会尝试大批量清理垃圾,所以它实际上可以在以后任意时间收集(或者永远不会在GC到达之前JVM终止)

旧答案

类卸载是一种罕见的事件,通常不会及时发生(如果有的话)。

具体来说,即使它有资格进行收集,也不会像Mono实例一样收集“普通”新对象 - 它通常位于一个特殊的不同池中(Oracle JVM中的PermGen)

你应该假设一旦加载一个类,它将永远保持加载状态。一旦你进入容器中的web应用程序,这并不总是正确的,但是那些在这些环境中工作过的人可以告诉你它一般有多好(不行)。

答案 1 :(得分:2)

Java中的垃圾收集通常是非确定性的,因为何时会发生以及当GC循环确实发生时GC将退出(“免费”)的符合条件的对象

唯一的可靠规则是:

  1. 只要强烈可达,对象将保持可用(不会被GC /释放/逐出)。 (参见Chapter 9 of Inside the Java Virtual Machine中的“物体的可达性生命周期”,这意味着什么 - 如果有点过时的话,一般来说读数非常好。)
  2. 在发布的代码中,remove将导致第二个对象new Mono(1, -1) 符合进行回收,因为不再有任何强引用(对象为否)更长的强烈可达性)。实际的驱逐(如果它发生)将在“稍后”发生,甚至可能不是下一个GC循环。使用终结器(ick)使问题更加复杂。

    请注意,一个对象永远不能保证是GC(例如,JVM可能正常地终止[ab])并且特定GC实现的确切语义可能不同而且仍然是符合虚拟机 - 这一切都归结为可达性。

    快乐的编码。

答案 2 :(得分:0)

你的意思是何时卸载了对象?

空列表仍然是一个列表,因此它将保留在内存中。你去的时候会被清除:

列表= somethingElse;

假设您没有指定任何其他内容列表。

就类定义本身而言,它应该永远留在内存中。类定义属于永久代。

作为旁注。列表不能在那时被垃圾收集。因为如果你清除它就可以添加它。

答案 3 :(得分:0)

无法卸载“Mono”类,因为仍有对它的引用。列表的类型引用它,列表中仍然有一个元素。

我想你并不是要问这个类是否被卸载,而是实例是否“卸载”。每个对象的每个实例都在堆上分配。当对象不再使用时,可以回收它在堆中占用的空间。然而,这不会立即发生。我所知道的所有JVM实现都使用垃圾收集器来清理内存。为了真正简化这里的事情:当没有更多空间可以在堆上创建新对象时,垃圾收集器会启动并检查堆的哪些部分仍在使用中。不再使用的部件可以重新用于新对象。

因此,来自不再使用的对象的内存只会在垃圾收集器启动时回收。而这是无法预测的。

答案 4 :(得分:0)

第二个对象在从列表中删除之后将有资格进行垃圾回收,因为不再有对它的引用..因此超出了范围。

希望这有帮助

答案 5 :(得分:0)

很多答案,所以这是我的旋转。想想“范围”,这是计算机语言中的一个概念,它描述了何时何地可以访问命名的内存。

这是您的原始代码,您声称删除了第二个列表成员:

LinkedList <Mono> list = new LinkedList ();

list.add(new Mono (2, 2));
list.add(new Mono (1, -1));
list.remove (1);
list.remove (2);`

在list.remove(2)处,仍然可以引用对象“list”。当然,它是空的,但是你可能决定添加一个新的Mono。你可以因为“list”仍然是范围,所以“list”不会被回收。

与此相比:

{
  LinkedList <Mono> list = new LinkedList ();

  list.add(new Mono (2, 2));
  list.add(new Mono (1, -1));
  list.remove (1);
  list.remove (2);`
}

在结束括号后,无法再引用“list”。 “list”在该范围内声明,当范围退出时,“list”与范围本身一起从命名空间中删除。在那个点,垃圾收集可能发生,因为没有人可能再次使用“列表”。

密切关注对象的范围。如果要影响垃圾收集,请将对象的范围限制为使用它们的区域。碰巧,这也是很好的编程风格。

答案 6 :(得分:0)

我猜人们对你使用的术语感到困惑。我相信你在询问你的Mono对象是否会被“删除”/“垃圾收集”。

让我们来看看你正在调用的remove(1) ......

这是您在java.util.LinkedList中定义的调用函数:

public E remove(int index) {
    return remove(entry(index));
}

上面的函数调用以下内容(查看我在代码中的注释):

private E remove(Entry<E> e) {
if (e == header)
    throw new NoSuchElementException();

    E result = e.element;
    e.previous.next = e.next; //Preceding element refers now to the one after the element to be removed;
    e.next.previous = e.previous; //Next element refers now to the one before the one to be removed;
    e.next = e.previous = null; //Element to be removed doesn't refer to anything anymore;
    e.element = null;
    size--;
    modCount++;
    return result;
}

在您调用的函数终止后,无法再引用您的Mono(1,-1)。 Mono对象不再可访问。这意味着它将符合垃圾收集的条件。请记住,“符合条件”可能意味着它永远不会被垃圾收集......更多关于GC here

答案 7 :(得分:0)

简单的答案是,当Java对象被垃圾回收时,对您来说无关紧要。您需要知道的唯一事情是 在程序内存不足之前收集 ... 提供该对象无法到达。

复杂的答案包括其他内容:

  • 垃圾收集器通常在您无法预测的时间运行。

  • 您可以调用System.gc()来建议JVM现在运行GC运行,但是:

    • JVM可能会忽略此提示,

    • 这样做通常是一个坏主意。 (运行GC非常昂贵,而且您的应用程序没有足够的信息来了解从效率的角度来看最好这样做的时间。)

  • 不保证任何特定的GC运行都会回收所有无法访问的对象。 GC有许多“智能”,旨在使GC尽可能高效,或减​​少“暂停”时间。其中一个“智能”是每次都不对整个堆进行GC。

  • 无法保证GC完全运行,或者它将在JVM关闭之前运行。

  • 由于上述原因,编写应用程序是糟糕的主意,因此依赖于在特定时间回收/删除的特定对象


应该关注你在内存管理方面的一件事是存储泄漏;例如,当你的应用程序保留对不必要的对象的引用,以防止这些对象变得无法访问。但这不是你的问题是什么约。)

答案 8 :(得分:0)

你的意思是Mono的实例是否有资格进行垃圾收集,或者是符合垃圾收集条件的列表实例?

单元实例在删除时将有资格进行垃圾收集(假设代码未通过对它的引用创建。

该列表不符合垃圾收集条件,因为它已清空。空列表不能被垃圾收集,因为它是一个可以再次读写的有效对象。

正如其他人所指出的那样。我们正在谈论有资格进行垃圾收集。垃圾收集器不一定立即运行。