Join GitHub today
[JENKINS-28844] Fix memory leak #54
This PR (I believe) fixes these issues:
@reviewbybees (who may want to know that this references ZD-26018)
- In larger installations of Jenkins the complex cycles of object references containing classloaders containing references to the channel which contains references back to the classloaders can confuse the garbage collector. - The confusion arrises because classloaders are considered live while there are objects from the classloader live and the RemoteClassLoader and RemoteInvocationHandler's proxy both need a reference to the Channel which typically can be storing either some of the objects from the RemoteClassLoader or the RemoteInvocationHandler's proxy instances in the Channel properties. Thus although the entire subgraph is no longer live, the cycle is not detected as ClassLoaders are treated separately. The issue is worse in Java 7 where the ClassLoaders are on the PermGen heap though it is also present in Java 8. - Typically multiple out of memory errors can cause the cycle to ultimately get cleaned up as one half gets cleared out breaking the cycle enough so that a subsequent out of memory removes the second half leaving a third out of memory to clear out the ClassLoaders... but after three out of memory errors in a row, Jenkins itself is typically well dead. This commit (I believe) fixes these issues: - We apply [Wheeler's theorem](http://en.wikipedia.org/wiki/Fundamental_theorem_of_software_engineering) to the Channel references. This allows us to clear out the reference instance as soon as the Channel is terminated thus simplifying the work of the garbage collector. - We move from using an Object.finalize() implementation to a PhantomReference implementation of the unexporting operation. In my experiments the call to Object.finalize() on a running Jenkins instance would very often get postponed to almost never, and more critically, the presence of a finalizer means that all instances of RemoteInvocationHandler were put in the finalizer queue as opposed to only those that need to be tracked for auto unexporting. We can (and do) proactively remove the references from the reference queue as soon as the channel is closed, further reducing the work that is required by the garbage collector.