6

I have an application that works heavily with many custom objects that are created inside methods and never needed outside of them. The whole structure is (in my opinion) very good object oriented and uses Services, Utilities and a DI-Model.

Now, as I ran my first "large" tests, I quickly encountered OutOfMemoryExceptions. Now, I don't just want to increase the heap space and be done with it, as I can imagine that will not solve the problem but rather delay it until my application has grown more and encounter the same problem then.

I'm looking for some simple and easy to implement solutions, tips and snippets that help an application deal with garbage collection and heap spaces, especially when it comes to many loops that operate with object creation.

Something like "don't create objects in loops, create them before the loop and overwrite it within" and the sorts.

trincot
  • 317,000
  • 35
  • 244
  • 286
F.P
  • 17,421
  • 34
  • 123
  • 189
  • I think if you could post some of your methods (atleast the structure) it would be a lot easier. see also http://stackoverflow.com/q/627784/1163434 – gawicks Mar 02 '12 at 13:39

5 Answers5

5

Some points:

  • There is nothing fundamentally wrong with increasing heap space. Different applications tend to have different requirements.
  • Use profiler to see what really is happening. For example here you can find heap analyzer: MAT
  • When you find out that instances of certain class are responsible of 80% of heap consumption:
    • try to find commonly shared set of variables with same values. Those are candidates to be one object which can be shared by multiple objects.
    • Check especially are you storing some reference to relatively big object graph to the variable that lives much longer than your loops (local variables consume stack).
    • Let references drop out of scope as fast as possible.
    • If you use inner classes, check ones that are not static, because non-static inner class holds reference to the containing object.
Mikko Maunu
  • 41,366
  • 10
  • 132
  • 135
4

The most important piece of advice that I can give you is the same as with any performance issue:

Profile, improve, repeat

Use a profiler (e.g. VisualVM) to find where the largest amount of memory is consumed. Improve your code, first to remove any memory leaks and then to reduce memory consumption in general. Repeat this process until you are satisfied with the quality and performance of your code.

EDIT:

A few tricks of the trade:

  • Share objects instead of duplicating, when possible.

  • Beware of the Java collection classes (i.e. the various Collection<T> and Map<K,V> implementations). Depending on what you are storing and what the collection in use is, you can easily increase your memory consumption by an order of magnitude without expecting it.

  • While Java does not (normally) have memory leaks in the same sense as encountered in C, Java code often has an issue with objects that are kept alive past their expiration date.

    To avoid this, limit the scope of your references as much as possible or set them to null when you are done with that object. Note: don't over do it with the null-setting, especially in trivial methods that are expected to return soon.

    Most importantly: make sure you remove an object from any collections it might have been entered into when you are done with it. Not doing so is a good recipe for an OutOfMemoryError - and the most common cause of what people call a memory leak in the Java world.

Community
  • 1
  • 1
thkala
  • 84,049
  • 23
  • 157
  • 201
2

I would start out by profiling your application and looking for memory hot spots by using the jvisualvm (part of the JDK). This will give you and indication of how large your objects are and what method calls are resulting in high memory use. It will also tell you how long your objects are haning around in memory which is generally a good starting point as you want to reduce scope to be as short as possible.

The next step is to identify commonalities in your objects either by refining your design or by implementing a cache. If you're loading data from a fixed store then you could use softreferences so as the JVM runs out of heap these objects will be GCed (if your making changes to these objects you will obviously need to persist them before removing the hard reference). Then if they are needed again your application will simply need to reload them from the backing store (DB, files or whatever).

Make sure you know how GC works and understand your object references:

  • Strong/Direct
  • Soft
  • Weak
  • Phantom

Here are a few good articles which explain references and GC:

http://www.java-tips.org/java-se-tips/java.util/using-weakhashmap-for-listener-lists.html

http://pawlan.com/monica/articles/refobjs/

http://www.kdgregory.com/index.php?page=java.refobj

NightWolf
  • 7,694
  • 9
  • 74
  • 121
0

Nullify any object reference as soon as an object is not needed anymore? As soon as an object has no more reference to it, the GC can collect it, but I am guessing that you already knew this. The GC can work also on unreferenced graph of objects (if A has the only reference to B and there are no more reference to A, then A and B can be collected).

It is almost pointless to call System.gc() since if the JVM needs more memory, it will do it on its own and then use the freed memory. If it cannot free any more memory then you run into OOME.

Now the default heap size is not that big and so it is often quite acceptable to require more heap size.

Creating objects in loops is not specifically a bad pattern and in many case it is quite relevant. What should be avoided is to repeatly instantiate the same object in a loop. Typically, string concatenation should be avoided in loops and be replaced by a StringBuilder created outside the loop, as it is a lot less efficient in terms of performance but not in terms of memory.

Not sure I really answer your question.

Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
0

Firstly, I would recheck my design, focusing on the needed upper complexity (Landau / Big O notation).

Secondly, I would read Josh Bloch's Effective Java, Item 6 (Eliminate obsolete object references), to get some hints about

  • frequent reasons for "memory leakage"
  • rather using the smallest scope possible then nullifying no longer needed objects
  • caching and storage pools.

Thirdly, if you still have OOM exceptions, I'd follow Mikko's advises.

Community
  • 1
  • 1
DaveFar
  • 7,078
  • 4
  • 50
  • 90