Java中的游荡对象垃圾收集
我在读Java中的垃圾收集,偶然发现了游荡的对象 这些对象被分配了内存,但没有被使用,也没有被垃圾收集。这些会不断增加JVM堆的大小,并表示内存泄漏,这可能会导致内存不足错误或垃圾收集器的开销过大Java中的游荡对象垃圾收集,java,garbage-collection,Java,Garbage Collection,我在读Java中的垃圾收集,偶然发现了游荡的对象 这些对象被分配了内存,但没有被使用,也没有被垃圾收集。这些会不断增加JVM堆的大小,并表示内存泄漏,这可能会导致内存不足错误或垃圾收集器的开销过大 任何人都可以提供这些游荡对象的代码示例。任何可以从GC根目录访问的对象都没有资格进行垃圾收集。GC根可能包括静态字段、线程本地存储和任何线程的堆栈 private static Object fieldThatIsNeverAccessed = new VeryLargeObject(); 即使在初
任何人都可以提供这些游荡对象的代码示例。任何可以从GC根目录访问的对象都没有资格进行垃圾收集。GC根可能包括静态字段、线程本地存储和任何线程的堆栈
private static Object fieldThatIsNeverAccessed = new VeryLargeObject();
即使在初始化后从未访问上述字段,其值以及该值直接或间接引用的任何对象仍将驻留在堆中。公共类缓存{
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) {
...
}
}
私有静态映射缓存=新HashMap();
公共静态整数计算(字符串s){
if(cache.containsKey){
返回cache.get;
}
否则{
整数结果=性能计算;
cache.put(s,result);
返回结果;
}
}
专用静态整数性能计算(字符串s){
...
}
}
上述方法试图通过使用计算值缓存来加快重复值的计算速度,这是一种明智的做法。但由于旧条目从未被删除,缓存会不断增长,直到没有可用的内存。旧问题,但我想我可能会将其清除。我发明了术语“游荡对象”这些对象仍被应用程序引用,但在语义上不再有用。游荡对象和泄漏对象之间的区别在于游荡对象最终会消失。游荡的一个主要示例是附加到HTTP会话的对象。会话将超时,连接的对象将消失但与此同时,他们将为过度内存消耗带来的所有问题负责 在“正常”内存泄漏的情况下,泄漏对象永远不会消失。这是应用程序逻辑中的一个缺陷,在这个缺陷中,您最有可能在技术上调整您的方法,以摆脱游荡的情况,解决正常内存泄漏的唯一方法是以后编写代码
虽然游荡和泄漏的结果可能相同,但区分两者有助于早期诊断问题。通常情况下,用户会在对话中抱怨内存不足错误。如果JVM能够从内存不足错误状态中恢复,那么您可以非常有信心您有一个游荡对象。在这种情况下,您可以查找断开保留在不需要的数据上的引用的用例。在大多数情况下,这将是一个计时器。JVM永远不会从正常内存泄漏中恢复。以下代码演示了使用数组实现堆栈,并提供了一个非常简单的游荡示例:
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的值时:数组[--N],
实际上,它将指针移到N-1处的索引,并将N处的索引移到null。
这里一个指针仍然指向null,尽管我们知道我们没有使用它,但JVM不知道。因此导致游荡,因为这个指针不会被JVM垃圾收集,即使它是null
我们可以通过如下更改代码来改进这一点:
public String pop(){
String s = array[--N];
array[N] = null;
return s;
}
这个版本避免了游荡,如果没有未完成的引用,垃圾收集器可以回收内存
<>希望有帮助!你能给我们提供一个对象的例子吗?从技术上讲,java在C++开发者的理解中不会有内存泄漏。游荡对象是描述所谓“内存泄漏”的另一种方式。在Java中,+1中包含了一个实际展示问题中提到的增长问题的示例。