Understanding Java Memory Management

46,951

Solution 1

The most important thing to remember about Java memory management is "nullify" your reference.

Only objects that are not referenced are to be garbage collected.

For example, objects in the following code is never get collected and your memory will be full just to do nothing.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) objs.add(new Object());

But if you don't reference those object ... you can loop as much as you like without memory problem.

List objs = new ArrayList();
for (int i = 0; i  < Integer.MAX_VALUE; i++) new Object();

So what ever you do, make sure you remove reference to object to no longer used (set reference to null or clear collection).

When the garbage collector will run is best left to JVM to decide. Well unless your program is about to start doing things that use a lot of memory and is speed critical so you may suggest JVM to run GC before going in as you may likely get the garbaged collected and extra memory to go on. Other wise, I personally see no reason to run System.gc().

Hope this helps.

Solution 2

Below is little summary I wrote back in the days (I stole it from some blog, but I can't remember where from - so no reference, sorry)

  1. There is no manual way of doing garbage collection in Java.
  2. Java Heap is divided into three generation for the sake of garbage collection. These are the young generation, tenured or old generation, and Perm area.
  3. New objects are created in the young generation and subsequently moved to the old generation.
  4. String pool is created in Perm area of Heap, Garbage collection can occur in perm space but depends on upon JVM to JVM.
  5. Minor garbage collection is used to move an object from Eden space to Survivor 1 and Survivor 2 space, and Major collection is used to move an object from young to tenured generation.
  6. Whenever Major garbage collection occurs application, threads stops during that period which will reduce application’s performance and throughput.
  7. There are few performance improvements has been applied in garbage collection in Java 6 and we usually use JRE 1.6.20 for running our application.
  8. JVM command line options -Xms and -Xmx is used to setup starting and max size for Java Heap. The ideal ratio of this parameter is either 1:1 or 1:1.5 based on my experience, for example, you can have either both –Xmx and –Xms as 1GB or –Xms 1.2 GB and 1.8 GB.

Command line options: -Xms:<min size> -Xmx:<max size>

Solution 3

Just to add to the discussion: Garbage Collection is not the only form of Memory Management in Java.

In the past, there have been efforts to avoid the GC in Java when implementing the memory management (see Real-time Specification for Java (RTSJ)). These efforts were mainly dedicated to real-time and embedded programming in Java for which GC was not suitable - due to performance overhead or GC-introduced latency.

The RTSJ characteristics

  • Immortal and Scoped Memory Management - see below for examples.
  • GC and Immortal/Scoped Memory can coexist withing one application
  • RTSJ requires a specially modified JVM.

RTSJ advantages:

  • low latency, no GC pauses
  • delivers predictable performance that is able to meet real-time system requirements

Why RTSJ failed/Did not make a big impact:

  • Scoped Memory concept is hard to program with, error-prone and difficult to learn.
  • Advance in Real-time GC algoritms reduced the GC pause-time in such way that Real-time GCs replaced the RTSJ in most of the real-time apps. However, Scoped Memories are still used in places where no latencies are tolerated.

Scoped Memory Code Example (take from An Example of Scoped Memory Usage):

import javax.realtime.*;
public class ScopedMemoryExample{

    private LTMemory myMem;

    public ScopedMemoryExample(int Size) {

       // initialize memory
       myMem = new LTMemory(1000, 5000); 
    }

public void periodicTask() {

  while (true)) {
    myMem.enter(new Runnable() {
        public void run() {
          // do some work in the SCOPED MEMORY
          new Object();
          ...
          // end of the enter() method, the scoped Memory is emptied.  
        }
    });
  }


}
}

Here, a ScopedMemory implementation called LTMemory is preallocated. Then a thread enters the scoped memory, allocates the temporary data that are needed only during the time of the computation. After the end of the computation, the thread leaves the scoped memory which immediately makes the whole content of the specific ScopedMemory to be emptied. No latency introduced, done in constant time e.g. predictable time, no GC is triggered.

Solution 4

You cannot avoid garbage collection if you use Java. Maybe there are some obscure JVM implementations that do, but I don't know of any.

A properly tuned JVM shouldn't require any System.gc() hints to operate smoothly. The exact tuning you would need depends heavily on what your application does, but in my experience, I always turn on the concurrent-mark-and-sweep option with the following flag: -XX:+UseConcMarkSweepGC. This flag allows the JVM to take advantage of the extra cores in your CPU to clean up dead memory on a background thread. It helps to drastically reduce the amount of time your program is forcefully paused when doing garbage collections.

Solution 5

From my experience, in java you should rely on the memory management that is provided by JVM itself.

The point I'd focus on in this topic is to configure it in a way acceptable for your use case. Maybe checking/understanding JVM tuning options would be useful: http://docs.oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm

Share:
46,951

Related videos on Youtube

Michael 'Maik' Ardan
Author by

Michael 'Maik' Ardan

Henlo

Updated on July 09, 2022

Comments

  • Michael 'Maik' Ardan
    Michael 'Maik' Ardan almost 2 years

    Java programmers know that JVM runs a Garbage Collector, and System.gc() would just be a suggestion to JVM to run a Garbage Collector. It is not necessarily that if we use System.gc(), it would immediately run the GC.

    Please correct me if I misunderstand Java's Garbage Collector.

    Is/are there any other way/s doing memory management other than relying on Java's Garbage Collector?
    If you intend to answer the question by some sort of programming practice that would help managing the memory, please do so.

    • omu_negru
      omu_negru over 11 years
      I think it boils down to the System.gc() call not being reliable, and not (always) freeing the resources that need to be freed when called. So if you have a tool you can't really rely on there aren't too many reasons for you to actually use it.
    • Affe
      Affe over 11 years
      JVM has malloc()'d a certain amount of space that is the heap. The operating system is obligated to have that much memory available to JVM. GC does not by rule always reduce that amount. Depending on how JVM is configured that number will not go below a certain amount no matter how few actual objects are in memory. Modern OS is smart enough to allow other processes to use the real physical memory and include swap space in the calculation of total reserved for JVM, but if you're in a position where this stuff is a concern in the first place, it may matter.
  • matbrgz
    matbrgz over 11 years
    With modern JVM's the amount of work needed to pool and reuse objects is much larger than the work needed just to allocate new, short-lived ones.
  • yshavit
    yshavit over 11 years
    @ThorbjørnRavnAndersen In most cases, yes. An application I'm working on (java-based RDBMS) has a case in which reusing objects helps significantly -- we reuse rows as we advance the cursor, and over a couple million rows it ends up being a big win. But again, we know this because we did the profiling to prove it.
  • matbrgz
    matbrgz over 11 years
    Then you have additional work besides mere allocation for an object to be reusable.
  • yshavit
    yshavit over 11 years
    @ThorbjørnRavnAndersen Yes, we do. But I consider that part of the same answer, because in practice an allocated chunk of zero'ed out bytes isn't very useful. In order to save on the other costs, we also have to take the hit of "manually" managing the memory management.
  • Michael 'Maik' Ardan
    Michael 'Maik' Ardan over 11 years
    @yshavit Please consider that I'm kinda new to JVM's memory management. When you said 'manually' do you mean that you have to nullify every single references?
  • yshavit
    yshavit over 11 years
    @MichaelArdan No, I mean rather than having each row be created as new Row(backingBytes) and then simply losing track of that row when we don't need it anymore (at which point it'll be eligible for GC), we create it once and then keep calling row.init(backingBytes) to go to the next row. But the point I tried to bring up in my answer, and which Thorbjørn emphasized, is that this is a rare case. In most all cases, you basically just need to make sure that a GC root (basically, any Thread or Runnable) doesn't hold onto objects longer that it needs to; the GC will take care of the rest.
  • Peter Butkovic
    Peter Butkovic over 11 years
    because at the end, that might be one of the few significant things you can do there. Of course, you should behave and keep referenced only those objects you really need, but generally from my experience, that's probably the only other thing you should keep in mind.
  • Michael 'Maik' Ardan
    Michael 'Maik' Ardan over 11 years
    Hello, this is very useful. Please explain further.
  • cambecc
    cambecc over 11 years
    Found this after a bit of googling: javarevisited.blogspot.jp/2011/04/…. It's a pretty good overview of how GC works in Java, included a description of concurrent-mark-and-sweep. The GC is one of the best things about the language. No more (well, much reduced) manual memory management compared to other languages like C++.
  • NawaMan
    NawaMan over 11 years
    Well, not everything. Local variables (as well as method parameters) will be cleared when the method call ends so you don't need to do that. Be aware of something sticky like static members (caches are the worst), on going threads or UI related objects and everything tide to all of them.
  • Michael 'Maik' Ardan
    Michael 'Maik' Ardan over 11 years
    This comment may be out of topic. But I just want to share this. I have seen a question regarding why Java is not widely used for commercial game development ( Yes, I'm aware of Runescape and MineCraft ). Some says that GC might pause the game for about a few seconds. I think this might be a solution if their only reason is GC being slow.
  • Aleš
    Aleš over 11 years
    These concepts are known since 1999 so there was enough time for their adoption. The reason why Java is not used in Game industry is probably different - perhaps that platform compilers and Game engines are still developed in C/C++.
  • Michael 'Maik' Ardan
    Michael 'Maik' Ardan over 11 years
    I see. Thank you very much Ales!