Java Memory Model Basics: Heap vs. Stack vs. Native Memory

Is troubleshooting and performance tuning Java applications part of your career plan? If you’re a developer, would you like to increase your skills in designing memory-efficient Java systems? If so, this article is for you. 

Understanding how the JVM organizes and manages memory is an important first step in avoiding memory-related issues. Let’s take a look at three of the terms that often come up when troubleshooting or configuring the JVM: heap, stack and native memory.

Heap, Stack and Native Memory

We’ll start by quickly defining these three terms, before taking a closer look at the Java memory model.

  • The Heap is the central storage area for all objects created in a Java program. It’s shared between all threads and all classes that make up the application. The heap memory is managed by the JVM rather than the operating system, and objects no longer in use are regularly removed by a background process known as the garbage collector.
  • The Stack is a memory area reserved for holding the context of running threads. It’s held in an area known as Thread Space, and each thread has its own stack. Each stack is made up of:
    • A pointer to the next instruction to be executed by the thread (the program counter.)
    • A frame for each active method in the thread. When a method is called, it’s pushed onto the stack. When it completes, it’s removed, or popped, from the stack. Among other things, the frame holds local variables if they are Java primitives. It also holds references (pointers) to the position in the heap of local variables that are objects.
  • Native memory refers to memory that is used by the JVM, but managed by the operating system. This is, in fact, all non-heap memory. The Thread Space containing the stack, for instance, is part of native memory. 

We’ll look in more detail at what native memory consists of in the next section.

For a more comprehensive explanation of the stack and the heap, and a worked example of how each is used when running a sample program, see Heap Memory and Stack Memory: What’s the Difference?

Putting It Together: The JVM Memory Model

We can visualize the JVM memory model like this:

Fig: The JVM Memory Model

The two primary divisions of JVM memory are the heap and native memory. Native memory is sometimes referred to as non-heap. 

Heap memory is managed by the JVM, and its size can be configured using command line arguments when the JVM is invoked. Heap space is regularly cleaned and compressed by the garbage collector.

The heap is divided into two main areas: the Young Generation (YG) and the Old Generation (OG). YG is generally smaller, and all new objects are created in this space. Since many objects in Java are short-lived, such as variables required for the duration of a single transaction, the YG is cleaned frequently. This is very fast, since the area is small. Any objects that survive a few cycles of garbage collection are deemed to be long-lived, and are moved to the OG. The OG is cleaned less frequently.

Native memory is managed by the operating system, and has several different memory pools:

  • Metaspace holds metadata related to classes, byte code for methods and other static data. In older JVMs this information was held in an area called the Permgen.
  • Thread Space contains the stack space for each running thread.
  • Code Cache contains pre-compiled machine code for ‘hot spots’ – frequently used methods.
  • Direct Buffers allow access to operating-system managed buffers for faster I/O.
  • GC is an area reserved for the garbage collector’s internal use.
  • JNI is used by the Java Native Interface.
  • Misc is reserved for the JVM’s internal use.

For a more comprehensive cover of JVM internals, I’d suggest watching JVM Explained in 10 Minutes.

If an application’s memory is under-configured, the application has a memory leak, or the hosting device runs short of overall memory, applications will crash with Out of Memory Errors. The first step in troubleshooting these errors is to look carefully at the error message to find out which area of memory has run out of space. 

There are 9 types of Out Of Memory errors that may occur in a Java application. Let’s briefly look at which area of memory each relates to.

  • Errors that relate to the heap include the following.
    • OutOfMemoryError: Java Heap Space: The heap has run out of space
    • OutOfMemoryError: GC Overhead Limit Exceeded: The heap has run out of space
    • OutOfMemoryError: Requested Array Size: The program is trying to create an array larger than the JVM limit
  • Errors that relate to native memory are:
    • OutOfMemoryError: Metaspace: The Metaspace has run out of space
    • OutOfMemoryError: Permgen Space: In JVM versions earlier than Java 8, the Permgen has run out of space. In later versions, the Permgen has been replaced by the Metaspace
    • OutOfMemoryError: Unable to create new native threads: The program is trying to create more threads than the operating system can provide.
    • OutOfMemoryError: Direct buffer memory: The direct buffer area has run out of space.
    • OutOfMemoryError: reason stack_trace_with_native_method: A function written in another language and called from the Java program has caused memory-related issues.
  • Error that relates to the device or container:
    • OutOfMemoryError: Kill Process or Sacrifice Child: The operating system has run out of memory and killed the Java application. This error appears in the kernel log rather than the application log.

Another memory-related error is StackOverflowError. This happens when a thread’s stack grows too large, and no more frames can be added to it. This is often caused by a program bug, but in some cases we may need to use JVM arguments to allow bigger stacks to be created. For more information, see StackOverflowError: Causes and Solutions.

Conclusion

The JVM memory model is not difficult to understand. Troubleshooting and performance tuning requires a working knowledge of how the JVM arranges and manages memory.

If you’d like to go deeper into JVM internals, you may like to look at yCrash’s JVM Performance Masterclass.

One thought on “Java Memory Model Basics: Heap vs. Stack vs. Native Memory

Add yours

Share your Thoughts!

Up ↑

Index

Discover more from HeapHero – Java & Android Heap Dump Analyzer

Subscribe now to keep reading and get access to the full archive.

Continue reading