Community
Participate
Working Groups
Build Identifier: M20091008-1320 I am a performance analyst for an adopting product. During memory runs (special GC settings to make memory measurements feasible), I have noticed differing values of memory use after our product simply comes up and is initialized (i.e. ready for work). Using core dumps and Eclipse MAT, I have found the problem and it is somewhat interesting. I haven't come across this type of problem in my 3 years of performance work yet. Here is the method org.eclipse.osgi.framework.eventmgr.EventManager.EventThread.run: /** * This method pulls events from * the queue and dispatches them. */ public void run() { try { while (true) { Queued item = getNextEvent(); if (item == null) { return; } EventManager.dispatchEvent(item.listeners, item.dispatcher, item.action, item.object); } ... The problem is that the loop local variable 'item' retains its previous value while the next call to getNextEvent() is blocked. I wouldn't have guessed it from the code, it looks like it should be cleared before the loop iterates again, but the bytecode shows that the compiler is not doing this. I thought that this might be a compiler bug, but looking at section 2.5.7 of the VM spec, (http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc.html#17203), it looks like the compiler is correct. I quote that section here: 7. Local variables are declared by local variable declaration statements. Whenever the flow of control enters a block or a for statement, a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block or for statement. The local variable is not initialized, however, until the local variable declaration statement that declares it is executed. The local variable effectively ceases to exist when the execution of the block or for statement is complete. So unless there is an explicit clearing of the 'item' variable, either at the end of the loop block or at the beginning before the call to getNextEvent(), the previous value will be retained during the call of the next iteration. This is bad for us as in our product, we are frequently seeing this object holding on to over 20 MB, completely needlessly. When I changed the first lines of the loop in the run() method to this: //Queued item = getNextEvent(); Queued item = null; item = getNextEvent(); Then I confirmed in the bytecode and by core dump that the memory was released. For us, this represents about 36% of our memory use after the product has loaded an empty workspace and inited itself. In my measurements, memory went from 64 MB without the change above to 41 MB with my change above. This is quite significant. Since this is not a hot method by any means, there should be no ill effects from making this change. Reproducible: Always Steps to Reproduce: Load up an Eclipse workbench, let it finish init'ing (so the even thread would be blocked in the getNextEvent() method--a Java would show this), take a heap/core/system dump. There will be one Java Local EventManager.EventThread.Queued (which is the item variable in the run method) instance for each EventManager.EventThread instance that is running. This should be cleared before blocking in getNextEvent().
Created attachment 156067 [details] Proposed patch.
Added a patch for the proposed change. Please backport to at least the 3.5 service stream, even the 3.4 if possible. Thanks.
John, please review for 3.5.2. Seems like a simple (if not rather strange) change to make. But since it shows significant memory improvements we should look to backport the fix TO 3.5.2 as well as release to HEAD.
Very interesting. It's equivalent, but the code might look a bit less strange if written like this: while (true) { Queued item = getNextEvent(); if (item == null) { return; } EventManager.dispatchEvent(...); //immediately clear item so it can be GC'd. See VM Spec 2.5.7 for why the //compiler will not automatically clear this variable for each loop iteration. item = null; } Anyway, +1 on either Randall's patch or the above
Created attachment 156130 [details] Upated patch Updated patch with John's suggestion. I agree with John that this makes the code a little more understanding.
Comment on attachment 156067 [details] Proposed patch. Thanks. Updating for IP log.
Patch released to HEAD and to 3.5.x stream.