Question about Java garbage collector, zeros and memory leak

Suppose I implement a queue in java, and I have a link to the starting node called ini and the other to the last called last. Now I am starting to insert objects into the queue. At some point, I decided that I needed an operation to clear the queue. Then I do this:

ini = null; last = null; 

Am I losing my memory? The nodes between ini and last are still chained and still have their own data, I think, but at the same time there is a garbage collector.

An alternative would be access to each element, and then zero references to the next node, but then I would do it as in C ++, but I would not use delete explicitly.

+4
source share
5 answers

As long as no items in the queue are mentioned anywhere in your code, the garbage collector will be able to return this memory. Setting pointers to null in Java is not the same as setting in C, where setting the malloc'ed pointer to null prevents it from being freed. In Java, memory is restored when it is no longer available. There are no memory leaks in Java (in the sense of C / C ++) unless you use native code through JNI.

A simplified garbage collector will simply count the number of references to an object and free this object when the reference count reaches zero, but it will not deal with reference loops (A → B, A → B → C → A, etc.). Java GC algorithms perform a survivability test, where they build a reference graph of all objects in the system. The GC traverses the graph, and any nodes (objects) that are not available are marked as unused and available for redistribution. The roots of the graph (the initial intersection points) include variables on the stack threads, static variables, and links stored in native code through the JNI. More details here: http://java.sun.com/developer/Books/performance/performance2/appendixa.pdf

Reference leaks are still possible. This applies to situations in which you hold a link to an object for longer than necessary. For instance:

 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--]; } } 

Ignoring the possibility of overflow / overflow, after calling Stack.pop (), the member variable of the array still has a reference to the returned object. This will prevent this garbage collection until the surrounding instance of Stack is no longer referenced. This is one of the rare cases when it is necessary to set a variable to zero so that its memory can be fixed:

 public Object pop() {Object ret = stack[top]; stack[top--] = null; return ret;} 
+19
source

It will work. The GC will detect that the nodes are unavailable, so they will all be cleaned.

+3
source

Yes, GC works in this case. But the elements between the head and tail can survive, and then enter the space of the old generation, and then they will be collected during the full GC. As you know, a full GC is expensive. As for performance, then zeroing them is better.

You can see how the clear () method of java.util.LinkedList is implemented.

 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/ affects the problem.

+3
source

If you suspect that you have a memory leak, I suggest you use a memory profiler to see how objects persist over time. A quick memory leak will be obvious with such a tool, so if you create a test for something that you suspect a leak and repeat it many times, you can see the leak and why the objects are saved.

0
source

Here is some code to demonstrate how a wandering descriptor in the middle of a list structure can completely clear the 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 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 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; } 
-1
source

All Articles