闲逛对象Java中的垃圾收集

时间:2013-11-23 16:32:47

标签: java garbage-collection

我正在阅读Java中的垃圾收集,我偶然发现了Loitering Objects。

这些对象分配了内存,但没有使用,也没有垃圾回收。这些不断增加JVM堆的大小并表示内存泄漏,这可能导致内存不足错误或垃圾收集器上的过多开销。

任何人都可以为这些游荡对象提供代码示例。

4 个答案:

答案 0 :(得分:4)

public class Cache {
    private static Map<String, Integer> cache = new HashMap<>();

    public static Integer compute(String s) {
        if (cache.containsKey(s) {
            return cache.get(s);
        }
        else {
            Integer result = performComputation(s);
            cache.put(s, result);
            return result;
        }
    }

    private static Integer performComputation(String s) {
        ...
    }
}

上述尝试通过使用计算值的缓存来加速计算重复值。但是,由于永远不会删除旧条目,因此缓存会增长并增长,直到没有可用内存为止。

答案 1 :(得分:1)

老问题,但我想我可能会清理它。我发起了术语“游荡对象”这些对象仍然被应用程序引用但在语义上不再有用。游荡物体和泄漏物体之间的区别在于游荡物体最终会消失。游荡的一个主要示例是附加到HTTP会话的对象。会话将超时,连接的对象将消失,但与此同时,他们将负责消耗过多的所有问题。

在“正常”内存泄漏的情况下,泄漏的对象永远不会消失。这是你的应用程序逻辑中的一个错误,因为你最有可能从技术上调整你的方式摆脱游荡情况,正常的内存泄漏的唯一方法是以后的代码。

虽然游荡和泄漏的结果可能相同,但区分两者可以帮助早期诊断问题。通常,您将进行一次对话,其中用户会抱怨内存不足错误。如果JVM能够从内存不足错误状态中恢复,那么您可以非常自信地拥有一个游荡对象。在这种情况下,您可以查找用于破坏不必要数据的引用的用例。在大多数情况下,这将是一个计时器。 JVM永远无法从正常的内存泄漏中恢复。

答案 2 :(得分:1)

以下代码演示了使用数组实现Stack,并提供了一个非常简单的游荡示例:

public class FixedCapacityStackOfStrings {

private String[] array;
private int N = 0;

public FixedCapacityStackOfStrings(int capacity) {
    array = new String[capacity];
}

public boolean isEmpty() {
    return N == 0;
}

public void push(String item){
    array[N++] = item;
}

public String pop(){
    return array[--N];
}}

注意,在代码中递减N的值:array [ - N], 它实际上将指针移动到N-1处的索引并且将N点处的索引转换为空。 这里指针仍指向null,即使我们知道我们没有使用它,但JVM不知道。因此导致游荡,因为即使它是null,这个指针也不会被JVM垃圾收集。

我们可以通过改变代码来改进这一点:

public String pop(){
    String s = array[--N];
    array[N] = null;
    return s;
}

此版本避免游荡,如果没有未完成的引用,垃圾收集器可以回收内存。

我希望它有所帮助!

答案 3 :(得分:0)

从GC根目录可以访问的任何对象都不符合垃圾回收的条件。 GC根可能包括静态字段,线程本地存储和任何线程的堆栈。

private static Object fieldThatIsNeverAccessed = new VeryLargeObject();

即使在初始化后从未访问过上述字段,其值以及该值直接或间接引用的任何对象仍将驻留在堆中。