7

This is a theoretical question. I am just curios that if Java has a mechanism for garbage collection to free the memory, then why does still OutOfMemoryError occur?

I searched SO for this but could get these links

Is the garbage collector guaranteed to run before Out of Memory Error?

Garbage collection before OutOfMemoryError

These do not answer my question specifically. If Java allows memory so well by using garbage collection, then why does OutOfMemoryError occur?

Community
  • 1
  • 1
Prasad Kharkar
  • 13,410
  • 5
  • 37
  • 56
  • 2
    If you dont put your rubish outside then the collectors wont be able to take it away. Same thing with Java, if for some reason you ar enot releasing references to your objects they wont be collected by the Garbage Collector. This is called a memory leak. – Luis Jun 25 '13 at 02:24
  • 1
    Garbage collection doesn't mean you have _infinite_ memory. – Louis Wasserman Jun 25 '13 at 02:25
  • Does SO allow acceptance of only one answer? I am trying to accept all but only one is being selected – Prasad Kharkar Jun 25 '13 at 02:38
  • @PrasadKharkar, yup only one accepted answer. If they're all equally good then I accept the first to answer and upvote the rest. – earcam Jun 25 '13 at 03:44
  • Yes I did the same :) – Prasad Kharkar Jun 25 '13 at 03:47

7 Answers7

12

An OutOfMemoryError can occur if none of the objects in memory is eligible for garbage collection. For example:

List<MyClass> hellos = new ArrayList<>();
for (;;) {
   hellos.add(new MyClass());
}

This creates a list and keeps adding MyClass objects to it until memory runs out. None of the objects is eligible for garbage collection because there are references to all of them.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • It completely slipped out of my mind that an infinite loop can cause infinite objects to be created and all have reference from the stack. Thank you sir :) This clears my doubt – Prasad Kharkar Jun 25 '13 at 02:30
  • 4
    @PrasadKharkar - You don't need an infinite loop. That's just a simple example. All you need is a problem where the amount of reachable data in the computation is too large for the heap ... at some time during the computation. – Stephen C Jun 25 '13 at 02:42
  • @StephenC, for `OutOfMemoryError` to occur, loop just needs to run long enough to take up all memory space, right? No need of infinite loop – Prasad Kharkar Jun 25 '13 at 02:44
  • 2
    @PrasadKharkar - You don't even need a loop! Just attempt to allocate a single VERY LARGE array. – Stephen C Jun 25 '13 at 02:45
3

It is also possible to sequester memory in ways you don't expect. Consider the following string example.

char[] chars      = new char[10_000_000];  // May need to adjust.
String string     = new String(chars);
chars             = null;
String substring  = string.substring(5_000_000);
string            = null; 

The chars array may be collected. The array inside string may not be collected, because substring contains a reference to the internal array followed by an offset and range into it. So, 107 characters remain allocated, even though only 5 * 106 are used and accessible.

Java 1.7.0_06

It seems that String.substring no longer has this behavior. In an article in the Java Performance Tuning Guide web site, Mikhail Vorontsov reports that in Java 1.7.0_06 and higher, String.substring always creates a new String independent of the old one. The String class no longer has offset and range instance variables. Creating a large string, taking substrings, and throwing away the original will not leave the old string's char[] sequestered.

// Java 1.7.0_06 and up
char[] chars      = new char[10_000_000];  // May need to adjust.
String string     = new String(chars);
chars             = null;
String substring  = string.substring(5_000_000);
// Copies a portion of string's array to a new array.
string            = null;
// string's array is no longer reachable, and may be garbage collected.
Eric Jablow
  • 7,874
  • 2
  • 22
  • 29
  • here, 'string' will be available in the memory but it will not be referred, right? This is because we are performing an operation on string object and as it is immutable, a new string will be created and the previous one will be lost – Prasad Kharkar Jun 25 '13 at 02:47
  • 1
    No, since `string` is immutable, there won't be any operations to change its contents. So, it's safe for the JVM to have `substring` reuse the `char[]` inside `string`. Then, when `string` is set to null, all the variables inside `string` can be collected, except for the array itself; `substring` refers to it. – Eric Jablow Jun 25 '13 at 02:50
2

Because not all memory is garbage.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • From my understanding, the garbage memory is the memory occupied by objects which cannot be referenced anymore from the program. Am I right? – Prasad Kharkar Jun 25 '13 at 02:56
  • That is correct. And if you keep asking for more and more memory that *can* be referenced by the program, you will run out. – user207421 Jun 25 '13 at 05:38
1

Garbage collector works on memory that is not going to be used.

However, if you allocate memory, and that memory is in scope, that means, garbage collector can't really clean that memory.

When the memory allocated is too high above the allowed for the VM, you get that exception.

mrcaramori
  • 2,503
  • 4
  • 29
  • 47
1

An object that's still has a reference to it from running code can't be collected. So if there's a way to even theoretically access an object, it's stuck in memory.

Just so it's said, Java doesn't eliminate the need to care about memory; it just automates a whole lot of the memory management stuff. You still have to do your part to ensure that you aren't squirreling away objects after their useful life is over...cause as long as they can be reached (however indirectly), they are taking up memory that can't be reclaimed.

cHao
  • 84,970
  • 20
  • 145
  • 172
  • Ohh yes, how come it slipped from mind that object creation in an infinite loop can create multiple objects and they will have references from the stack. Thank you @cHao , this helped me :) – Prasad Kharkar Jun 25 '13 at 02:27
0

It is better to nullify your objects once your work has been completed with them, so you make sure the objects to be available to the garbage collector in order to avoid the problems regarding out of memory or memory leak.

Annaji
  • 9
  • 1
  • This is not that easy. What if multiple references refer to same object. In this case if you nullify the object then there is a chance of dangling reference!!! So nullify the object is not the solution always!!! – Narendra Jun 25 '13 at 03:16
  • Setting object references to `null` is usually a complete waste of time. Method-local references fall out of scope anyway, and references that are instance variables aren't that easy to set to null at arbitrary times, unless they should really be local variables, in which case they will fall out of scope anyway ... – user207421 Jun 25 '13 at 05:40
0

If you run out of memory and there is no variable or object eligible for removing, the except will be raised.

So best way to use GC(Garbage collection) is:

Explicitly assign the variable to null value if it is no used any more.

Jeremy Zhou
  • 49
  • 1
  • 4