Garbage Collection in Java with Recursive Function

烂漫一生 提交于 2020-01-24 04:52:09

问题


I know that objects become unreachable and marked for garbage collection in every iteration of a regular loop. What about recursive calls? Something like:

public void doWork() {

    Object a = new Object();

    ....some work with a...

    this.sleep(60000);
    doWork();


  }

Is the object (i.e. 'a') in the first recursion marked for garbage collection once the second recursion begins or does it need to be explicitly marked null since the outer function never finishes because of the recursion.


回答1:


During each recursive call the local variables(here the reference "a") are pushed onto the stack. Local variable are GC roots. During the second recursive call the new reference is pushed onto the stack. However, the first reference is still there and thus the object is still reachable and thus can't be garbage collected.

Thus if you want the first created object to be marked for garbage collection(while the function hasn't yet finished) you should explicitly set "a" to null.

Here is a useful link to understand GC: http://javabook.compuware.com/content/memory/how-garbage-collection-works.aspx




回答2:


I have found that local variables referencing objects are garbage collected if they are no longer needed. However, this does not apply when debugging. I guess the debugger keeps a reference to it, but in regular execution there is no need for it.

Try executing the following code, and see what happens.

Object o1 = new Object();
System.out.println(o1);
WeakReference<Object> wr = new WeakReference<Object>(o1);
System.gc();
System.out.println(wr.get());

My output (without debugger):

java.lang.Object@20662d1
null

My output (with debugger):

java.lang.Object@206b4fc
java.lang.Object@206b4fc

It would therefore appear that the earlier references are garbage collected, even when the local method is still on the stack.




回答3:


Is the object (i.e. 'a') in the first recursion marked for garbage collection once the second recursion begins or does it need to be explicitly marked null since the outer function never finishes because of the recursion.

The answer is ... it is platform dependent.

The variable a is still in-scope until the declaring instance of doWork() returns. On the other hand, it is obvious to us that by the time the a variable cannot influence the computation once we reach the recursive call, and (in theory) that means that the GC no longer needs to consider it for the purposes of determining reachability.

So, it boils down to whether or not the JVM is smart enough to realize that a doesn't matter any more. That is platform dependent. And as another Answer notes, running with a debugger attached can change this.


Another Answer mentions tail-call optimization. Certainly, if a JVM did implement this optimization, then the "old" a would conceptually be replaced by a "new" one in the optimized "call". However, no HotSpot JVM (at least up to Java 8) implements tail-call optimization because the optimization would interfere with Java code that relies on being able to count stack frames; e.g. security code.

However, if this particular code was a significant storage leak, then it would most likely be moot, because (absent tail-call optimization) the code is likely to give you a StackOverflowError before it fills the heap.




回答4:


You should asume that all local references are alive as long as the method itself is in the call stack. This means you get one alive reference to a for each recursion.

It might happen that the runtime sees, that the slot for variable a can be overwritten when it is no longer accessed. In that case it becomes unreachable even when doWork() has not returned yet. However you cannot rely on this. It would help to a = null; right after last usage of a.




回答5:


Theoretically, recursion is done by pushing the actual frame (local variable set) onto the stack and opening a new frame for the new execution.

The object in the heap are still referred by variables in the frame that has been pushed to the stack and that means that, for the GC, the object is still "live".

However many compilers (and I assume javac as well) are able to recognize and unfold tail recursions like the one in the example, thus simplifying the recursion quite a lot a freeing many resources.

In general, however, recursion uses up a lot of stack and heap space and that's why using recursion is not always a good idea.




回答6:


It is a good approach to actively get rid of references if you want garbage collection, by setting your variables to null. However, do not forget that objects might contain event registration, separate threads and so on, so if you want to garbage-collect an object, you must make sure there is no leak in their references. This is not the case with Object, but it can happen with instances from other classes. As for the question though, I believe that it is not garbage-collected unless you get rid actively from its reference, but I have not tested this with all Java versions.



来源:https://stackoverflow.com/questions/27781116/garbage-collection-in-java-with-recursive-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!