We know that a memory leak can occur in Java applications when object references are unintentionally held onto after the references are no longer needed. Typical examples of these are large collection objects, a unbounded cache, large number of session objects, infinite loops etc. A memory leak results in a OutOfMemoryError.
Besides this core reason, there are other factors that may also result in a OutOfMemoryError exception
1. Java heap fragmentation: Heap fragmentation occurs when no contiguous chunk of free Java heap space is available from which to allocate Java objects. Various causes for this problem exist, including the repeated allocation of large objects (no single large fragment in first generation). In this case, even if we see good amount of free heap, memory allocation fails.
2. Memory leaks in native heap. This problem occurs when a native component, like database connections, is leaking.
3. Perm size has exhausted. The permanent generation of the heap contains class objects. If your code is using a lot of reflection/introspection, then a number of temporary class objects are created that would exhaust the perm space. More info can be found here.