- Java memory management
- Java memory model
- Heap memory
- Non-heap memory
- Direct memory
- Java garbage collection
- Java memory configurations
- Java containerization
- Important JVM options
- Default maximum memory size
- Default maximum heap size
- Default maximum direct memory size
- Memory usage layout
- Java OOM
- See also
- How to control Java heap size (memory) allocation (xmx, xms)
- Java RAM: Short answer
- Java RAM: The longer answer
- Setting the maximum Java heap size (Xmx)
- More Java memory-related command line arguments
- Java heap size descriptions (xms, xmx, xmn)
- Java memory arguments (xms, xmx, xmn) formatting (MB, GB)
Java memory management
Azure Spring Apps is the new name for the Azure Spring Cloud service. Although the service has a new name, you’ll see the old name in some places for a while as we work to update assets such as screenshots, videos, and diagrams.
This article applies to: ✔️ Basic/Standard ✔️ Enterprise
This article describes various concepts related to Java memory management to help you understand the behavior of Java applications hosted in Azure Spring Apps.
Java memory model
A Java application’s memory has several parts, and there are different ways to divide the parts. This article discusses Java memory as divided into heap memory, non-heap memory, and direct memory.
Heap memory
Heap memory stores all class instances and arrays. Each Java virtual machine (JVM) has only one heap area, which is shared among threads.
Spring Boot Actuator can observe the value of heap memory. Spring Boot Actuator takes the heap value as part of jvm.memory.used/committed/max . For more information, see the jvm.memory.used/committed/max section in Tools to troubleshoot memory issues.
Heap memory is divided into young generation and old generation. These terms are described in the following list, along with related terms.
- Young generation: all new objects are allocated and aged in young generation.
- Eden space: new objects are allocated in Eden space.
- Survivor space: objects will be moved from Eden to survivor space after surviving one garbage collection cycle. Survivor space can be divided to two parts: s1 and s2.
Before Java 8, another section called permanent generation was also part of the heap. Starting with Java 8, permanent generation was replaced by metaspace in non-heap memory.
Non-heap memory
Non-heap memory is divided into the following parts:
- The part of non-heap memory that replaced the permanent generation (or permGen) starting with Java 8. Spring Boot Actuator observes this section and takes it as part of jvm.memory.used/committed/max . In other words, jvm.memory.used/committed/max is the sum of heap memory and the former permGen part of non-heap memory. The former permanent generation is composed of the following parts:
- Metaspace, which stores the class definitions loaded by class loaders.
- Compressed class space, which is for compressed class pointers.
- Code cache, which stores native code compiled by JIT.
Direct memory
Direct memory is native memory allocated by java.nio.DirectByteBuffer , which is used in third party libraries like nio and gzip.
Spring Boot Actuator doesn’t observe the value of direct memory.
The following diagram summarizes the Java memory model described in the previous section.
Java garbage collection
There are three terms regarding of Java Garbage Collection (GC): «Minor GC», «Major GC», and «Full GC». These terms aren’t clearly defined in the JVM specification. Here, we consider «Major GC» and «Full GC» to be equivalent.
Minor GC performs when Eden space is full. It removes all dead objects in young generation and moves live objects to from Eden space to s1 of survivor space, or from s1 to s2.
Full GC or major GC does garbage collection in the entire heap. Full GC can also collect parts like metaspace and direct memory, which can be cleaned only by full GC.
The maximum heap size influences the frequency of minor GC and full GC. The maximum metaspace and maximum direct memory size influence full GC.
When you set the maximum heap size to a lower value, garbage collections occur more frequently, which slow the app a little, but better limits the memory usage. When you set the maximum heap size to a higher value, garbage collections occur less frequently, which may create more out-of-memory (OOM) risk. For more information, see the Types of out-of-memory issues section of App restart issues caused by out-of-memory issues.
Metaspace and direct memory can be collected only by full GC. When metaspace or direct memory is full, full GC will occur.
Java memory configurations
The following sections describe important aspects of Java memory configuration.
Java containerization
Applications in Azure Spring Apps run in container environments. For more information, see Containerize your Java applications.
Important JVM options
You can configure the maximum size of each part of memory by using JVM options. You can set JVM options by using Azure CLI commands or through the Azure portal. For more information, see the Modify configurations to fix problems section of Tools to troubleshoot memory issues.
The following list describes the JVM options:
- Heap size configuration
- -Xms sets the initial heap size by absolute value.
- -Xmx sets the maximum heap size by absolute value.
- -XX:InitialRAMPercentage sets the initial heap size by the percentage of heap size / app memory size.
- -XX:MaxRAMPercentage sets the maximum heap size by the percentage of heap size / app memory size.
- -XX:MaxDirectMemorySize sets the maximum direct memory size by absolute value. For more information, see MaxDirectMemorySize in the Oracle documentation.
- -XX:MaxMetaspaceSize sets the maximum metaspace size by absolute value.
Default maximum memory size
The following sections describe how default maximum memory sizes are set.
Default maximum heap size
Azure Spring Apps sets the default maximum heap memory size to about 50%-80% of app memory for Java apps. Specifically, Azure Spring Apps uses the following settings:
Default maximum direct memory size
When the maximum direct memory size isn’t set using JVM options, the JVM automatically sets the maximum direct memory size to the value returned by Runtime.getRuntime.maxMemory(). This value is approximately equal to the maximum heap memory size. For more information, see the JDK 8 VM.java file.
Memory usage layout
Heap size is influenced by your throughput. Basically, when configuring, you can keep the default maximum heap size, which leaves reasonable memory for other parts.
The metaspace size depends on the complexity of your code, such as the number of classes.
The direct memory size depends on your throughput and your use of third party libraries like nio and gzip.
The following list describes a typical memory layout sample for 2-GB apps. You can refer to this list to configure your memory size settings.
- Total Memory (2048M)
- Heap memory: Xmx is 1433.6M (70% of total memory). The reference value of daily memory usage is 1200M.
- Young generation
- Survivor space (S0, S1)
- Eden space
- Observed part (observed by Spring Boot Actuator)
- Metaspace: the daily usage reference value is 50M-256M
- Code cache
- Compressed class space
- Thread stack
- GC, internal symbol and other
The following diagram shows the same information. Numbers in grey are the reference values of daily memory usage.
Overall, when configuring maximum memory sizes, you should consider the usage of each part in memory, and the sum of all maximum sizes shouldn’t exceed total available memory.
Java OOM
OOM means the application is out of memory. There are two different concepts: container OOM and JVM OOM. For more information, see App restart issues caused by out-of-memory issues.
See also
How to control Java heap size (memory) allocation (xmx, xms)
Java/Scala memory FAQ: How do I control the amount of memory my Java program uses (i.e., Java RAM usage)?
Java RAM: Short answer
The short answer is that you use these java command-line parameters to help control the RAM use of application:
- Use -Xmx to specify the maximum heap size
- Use -Xms to specify the initial Java heap size
- Use -Xss to set the Java thread stack size
Use this syntax to specify the amount of memory the JVM should use:
-Xms64m or -Xms64M // 64 megabytes -Xmx1g or -Xmx1G // 1 gigabyte
A complete java command looks like this:
See the rest of this article for more details. Also see my Java heap and stack definitions if you’re not comfortable with those terms.
Java RAM: The longer answer
As a bit of background, I’m running a Java application on a Raspberry Pi device where memory is limited. Unfortunately, every time I try to run the program I get this Java heap size error message:
“Error occurred during initialization of VM. Could not reserve enough space for object heap. Could not create the Java virtual machine.”
I knew my program doesn’t need a lot of memory — it was just hitting a database and generating some files and reports — so I got around this memory limit problem by specifying the maximum Java heap size my program was allowed to allocate. In my case I didn’t think about it too hard and just chose a heap size limit of 64 MB RAM, and after I set this RAM limit my program ran fine.
Setting the maximum Java heap size (Xmx)
You set the maximum Java heap size of your program using the -Xmx option to the Java interpreter. To specifically limit your heap size to 64 MB the option should be specified like this:
Using that memory limit setting, the Java command I use in my shell script to start my Java program looks like this:
where THE_CLASSPATH and PROGRAM_NAME are variables set earlier in my script. (The important part here is the -Xmx64m portion of the command.)
More Java memory-related command line arguments
You can find more options for controlling Java application memory use by looking at the output of the java -X command. Here’s what the output of those commands looks like from my JVM:
$ java -X -Xmixed mixed mode execution (default) -Xint interpreted mode execution only -Xbootclasspath:
set search path for bootstrap classes and resources -Xbootclasspath/a: append to end of bootstrap class path -Xbootclasspath/p: prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection -Xloggc: log GC status to a file with time stamps -Xbatch disable background compilation -Xms set initial Java heap size -Xmx set maximum Java heap size -Xss set java thread stack size -Xprof output cpu profiling data -Xfuture enable strictest checks, anticipating future default -Xrs reduce use of OS signals by Java/VM (see documentation) -Xdock:name= override default application name displayed in dock -Xdock:icon= override default icon displayed in dock -Xcheck:jni perform additional checks for JNI functions -Xshare:off do not attempt to use shared class data -Xshare:auto use shared class data if possible (default) -Xshare:on require using shared class data, otherwise fail. The -X options are non-standard and subject to change without notice. From that list, the command-line arguments specifically related to Java application memory use are:
-Xnoclassgc disable class garbage collection -Xms
set initial Java heap size -Xmx set maximum Java heap size -Xss set java thread stack size Java heap size descriptions (xms, xmx, xmn)
Digging around, I just found this additional Java xms , xmx , and xmn information on Apple’s web site:
-Xms size in bytes Sets the initial size of the Java heap. The default size is 2097152 (2MB). The values must be a multiple of, and greater than, 1024 bytes (1KB). (The -server flag increases the default size to 32M.) -Xmn size in bytes Sets the initial Java heap size for the Eden generation. The default value is 640K. (The -server flag increases the default size to 2M.) -Xmx size in bytes Sets the maximum size to which the Java heap can grow. The default size is 64M. (The -server flag increases the default size to 128M.) The maximum heap limit is about 2 GB (2048MB).
Java memory arguments (xms, xmx, xmn) formatting (MB, GB)
When setting the Java heap size, you should specify your memory argument using one of the letters “m” or “M” for MB, or “g” or “G” for GB. Your setting won’t work if you specify “MB” or “GB.” Valid arguments look like this:
Also, make sure you just use whole numbers when specifying your arguments. Using -Xmx512m is a valid option, but -Xmx0.5g will cause an error.
- Young generation