我正在阅读Java中的垃圾收集,我偶然发现了Loitering Objects。
这些对象分配了内存,但没有使用,也没有垃圾回收。这些不断增加JVM堆的大小并表示内存泄漏,这可能导致内存不足错误或垃圾收集器上的过多开销。
任何人都可以为这些游荡对象提供代码示例。
答案 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();
即使在初始化后从未访问过上述字段,其值以及该值直接或间接引用的任何对象仍将驻留在堆中。