假设我在java中实现了一个队列,我引用了一个名为ini的初始节点,另一个名为last的引用。现在,我开始将对象插入队列。有一次,我决定要一个清除队列的操作。然后我这样做:
ini = null;
last = null;
我是否在泄漏记忆?我想,ini和last之间的节点都是链接的,但仍有数据,但同时还有垃圾收集器。
另一种方法是访问每个元素,然后将它们对下一个节点的引用置空,但是我基本上就像在C ++中一样,除了我不会明确地使用delete。
答案 0 :(得分:19)
只要代码中的任何其他位置都没有引用队列中的项,垃圾回收器就能够回收该内存。在Java中将指针设置为null与C中的指针不同,其中将malloc指定的null设置为阻止它被释放。在Java中,当内存不再可访问时,内存将被回收。只要您没有通过JNI使用本机代码,Java中就没有内存泄漏(在C / C ++意义上)。
简单的垃圾收集器只计算对象的引用数,并在引用计数达到零时解除分配该对象,但这将无法处理引用周期(A - > B,A - > ; B - > C - > A等)。 Java GC算法进行活性测试,在这里他们构建系统中所有对象的参考图。 GC执行图遍历,任何无法访问的节点(对象)都标记为未使用且可用于重新分配。图的根(遍历的起始行)包括线程堆栈上的变量,静态变量和本机代码通过JNI持有的引用。点击此处:http://java.sun.com/developer/Books/performance/performance2/appendixa.pdf
仍然可能有引用泄漏。这指的是您持续对对象的引用超过所需时间的情况。例如:
public class Stack {
private final Object[] stack = new Object[10];
private int top = 0;
public void push(Object obj) {stack[top++] = obj;}
public Object pop() {return stack[top--]; }
}
忽略溢出/下溢的可能性,在调用Stack.pop()之后,数组成员变量仍然具有对返回的对象的引用。它将阻止该对象被垃圾收集,直到不再引用周围的Stack实例。这是必须将变量设置为null以便可以回收其内存的罕见情况之一:
public Object pop() {Object ret = stack[top]; stack[top--] = null; return ret;}
答案 1 :(得分:3)
这样可以正常工作。 GC将检测到节点无法访问,因此它们都将被清除。
答案 2 :(得分:3)
是的,GC适用于这种情况。 但是头部和尾部之间的元素可以存活,然后进入老一代空间 它们将在完整的GC期间收集。 如您所知,完整的GC价格昂贵。就性能而言,将它们归零会更好。
您可以看到如何实现java.util.LinkedList的clear()方法。
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
e.next = e.previous = null;
e.element = null;
e = next;
}
header.next = header.previous = header;
size = 0;
modCount++;
}
http://tech.puredanger.com/2009/02/11/linkedblockingqueue-garbagecollection/触及了这个问题。
答案 3 :(得分:0)
如果您怀疑内存泄漏,我建议您使用内存分析器查看对象随时间的保留情况。使用这样的工具会出现快速内存泄漏,因此如果您为怀疑泄漏的内容创建测试并重复多次,您将能够看到泄漏以及保留对象的原因。
答案 4 :(得分:-1)
这里有一些代码来演示列表结构中间的杂散句柄如何防止GC完全清理:
import java.lang.ref.*;
public class MemoryLeak1 {
MyListItem leakedItem = null;
WeakReference[] refs = null;
public static void main(String[] args) {
WeakReference ref = null;
MyListItem item = null;
MemoryLeak1 leak = new MemoryLeak1();
int i;
leak.doit(); // create a memory leak
System.gc(); // force the gc to run;
// At this point the list has been explicitly cleared,
// has gone out of scope, and the GC has run.
// However, leak.leakedItem is still holding a
// reference to an item in the list, so anything
// reachable from that item is still alive.
// show what's still around...
for (i = 0; i < 10; i++) {
ref = leak.refs[i];
item = (MyListItem)ref.get();
if (item == null) { System.out.println("" + i + " = null"); }
else { System.out.println("" + i + " = " + (String)item.thing); }
}
System.out.println("---------------------");
// now let's free some additional items...
for (i = 1; i <= 3; i++) {
item = leak.leakedItem;
leak.leakedItem = item.next;
leak.leakedItem.prev = null;
item.prev = null;
item.next = null;
}
item = null;
System.gc(); // force the gc to run again
// this time we should get fewer items
for (i = 0; i < 10; i++) {
ref = leak.refs[i];
item = (MyListItem)ref.get();
if (item == null) { System.out.println("" + i + " = null"); }
else { System.out.println("" + i + " = " + (String)item.thing); }
}
System.out.println("---------------------");
// now clear the last reference
leak.leakedItem = null;
System.gc(); // force the gc to run again
// this time we should none
for (i = 0; i < 10; i++) {
ref = leak.refs[i];
item = (MyListItem)ref.get();
if (item == null) { System.out.println("" + i + " = null"); }
else { System.out.println("" + i + " = " + (String)item.thing); }
}
System.out.println("---------------------");
}
public void doit() {
this.refs = new WeakReference[10];
MyList list = new MyList();
MyListItem item = null;
// add strings to the list.
// set each into the array of soft refs
// set a ptr to the 6th item in an instance variable
for (int i = 0; i < 10; i++) {
item = new MyListItem();
item.thing = new String("string" + i);
list.insert(item);
if (i == 5) this.leakedItem = item;
this.refs[i] = new WeakReference(item);
}
// clear the list, but don't clear the
// additional ptr to the 6th item
list.clear();
}
}
class MyList {
MyListItem head = null;
MyListItem tail = null;
void clear() {
head = null;
tail = null;
}
void insert(MyListItem item) {
if (head == null) {
// empty list
item.next = null;
item.prev = null;
tail = item;
head = item;
}
else if (head == tail) {
// one item in list
item.next = head;
item.prev = null;
tail = head;
head = item;
}
else {
// multiple items in list
item.next = head;
item.prev = null;
head = item;
}
}
MyListItem remove() {
MyListItem item = tail;
if (item != null) {
tail = item.prev;
if (tail == null) {
head = null;
}
else {
tail.next = null;
}
item.next = null;
item.prev = null;
}
return item;
}
}
class MyListItem {
MyListItem next = null;
MyListItem prev = null;
Object thing = null;
}