Measuring Memory While a Web Agent Runs

When I run a Java web agent concurrently it often fails with the following error.

HTTP JVM: AgentBase Error: java.lang.OutOfMemoryError

HTTP JVM: java.lang.OutOfMemoryError

To monitor the agent’s memory consumption, the following code has been added to the agent:

Runtime.getRuntime().freeMemory();

The agent still often runs to completion when the free memory is relatively low - for example, 5 percent of what’s returned by Runtime.getRuntime().totalMemory().

It was my understanding that Runtime.getRuntime() refers to memory from the Domino JVM. However, the above error message is apparently a result of insufficient memory in the ‘system’ JVM.

I’m therefore interested in how the free memory associated with the ‘system’ JVM can be measured. This might better explain why the agent often fails while running concurrently.

A few things to note:

  • ‘topas’ does not show changes in the system memory while the agent runs.

  • The JavaMaxHeapSize has been increased.

  • The Java code does garbage collection and recycling.

  • JAR’s used by the agent have been copied to the lib/ext directory.

Thanks.

Subject: Measuring Memory While a Web Agent Runs

The error doesn’t necessarily mean the JVM is running out of memory. See the link below for other situations that can cause the same error:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4212479

I think that overflowing a String can also cause this error (not sure but think it could be a 16MB limit on strings).

You need to zero in on the code that causes the error. In order to do that, you’ll need to change your “catch” statements to “catch( Throwable e )” instead of “catch( Exception e )”. This will enable you to catch System errors, which are not Exceptions but rather Errors.

If I remember correctly, you may not be able to print a stacktrace when an Error is thrown, so you’ll have to be creative (try e.printStacktrace, but I’m thinking it won’t give you anything useful). Send messages to “System.out” followed by “System.out.flush()” to try to force messages to the server log. Send out “progress” messages so you can tell how far your code got before it experiences the error. Using this technique, start at the outermost code and then add the messages to the subroutines that is failing and then within that subroutine to the subroutines it calls, effectively zooming in on the location where the error is occurring.

Once you can figure out which line of code is the offending code, do a Google search. It could be a known problem that has a solution.

If you still can’t figure it out, post a response to this thread, I’ll be getting updates on it, and I can see if I can help you further.

If you are using a URLConnection, I can tell you right now that the solution is not to use URLConnection to upload a large amount of content. You’ll have to switch over to something like Jakarta HttpClient (Google it).

Hope this helps.

Subject: RE: Measuring Memory While a Web Agent Runs

Martin … thanks for the response. The amount of data being transferred is not significant and so it does not seem likely that this would be causing the out of memory error. What I failed to mention is that the errors occur more often after multiple runs of the agent. In other words, the effect is cumulative.

The agent measures the Domino JVM memory by using Runtime.getRuntime().freeMemory(). However, if the errors are related to the memory in the ‘system’ JVM, how might this be measured?

Thanks.

Subject: RE: Measuring Memory While a Web Agent Runs

You may then have a true memory resource issue. You may need to be more agressive about garbage collection and need to optimize your code further.

By the way, there is a difference between freeMemory and totalMemory, I think freeMemory is the maximum available contiguous memory block availalbe. Your problem could be memory fragmentation, even though you have enough overall memory available. Another problem is how Domino allocates memory. I believe all agent threads work off of the same pool of JVM memory and the more activity on the server there is, the more fragmented the memory becomes. You may want to have your Domino service restarted and see if the code runs to completion immediately after a restart. If it does, you may want to restart the service nightly.

private void tryFreeingUpMemory() {

	

	System.out.println( "Total Memory Before = " + Runtime.getRuntime().totalMemory() );

	System.out.println( "Available Memory Before = " + Runtime.getRuntime().freeMemory() );



	Runtime.getRuntime().runFinalization();

	Runtime.getRuntime().gc();

	

	System.out.println( "Total Memory After = " + Runtime.getRuntime().totalMemory() );

	System.out.println( "Available Memory After = " + Runtime.getRuntime().freeMemory() );

}

The function above runs finalization and garbage collection, hopefully that could free up some memory. You can try peppering into your code before and after any complex or memory intensive routines.

As far as optimizing your code, if you use Eclipse there are a LOT of plugins. I’ve used AppPerfect before and learned a lot about Java optimization. http://www.appperfect.com/ Two quickies are using StringBuffers instead of strings whenever possible and declaring objects final when you want to garbage collect more agressively.

As far as Domino optimization, you absolutely need to make sure that if you are traversing a list of Documents through a view or collection of some kind that you use Recycle.

If you need more details, write me back, I’ll be keeping an eye on this thread. Hope this helps.