This article is participating in “Java Theme Month – Java Debug Notes Event”, see < Event link > for more details.

You might be bored when you see a configuration like the following. This is how the JVM parameters are configured.

/usr/local/jdk/bin/java -Dresin.home=/usr/local/resin -server -Xms1800M -Xmx1800M -Xmn300M -Xss512K -XX:PermSize=300M -XX:MaxPermSize=300M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:GCTimeRatio=19 -Xnoclassgc -XX:+DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log
Copy the code

Here’s what each parameter means and how to adjust it.

Set heap size

There are three limitations to the maximum heap size in the JVM: the data model (32-bit or 64-bit) of the relevant operating system; The virtual memory limit available to the system; The available physical memory limit of the system. In a 32-bit system, the value ranges from 1.5 GB to 2 GB. 64 indicates that the OS has no memory limit. I tested in Windows Server 2003 system, 3.5G physical memory, JDK5.0, the maximum can be set to 1478M. Typical Settings:

  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k

** -XMX3550M: ** Sets the maximum available memory of the JVM to 3550M.

** -xMS3550M: ** Sets the JVM to drive 3550m memory. This value can be set to the same as -xmx to avoid the JVM reallocating memory after each garbage collection.

** -xmn2G: ** Sets the size of the young generation to 2G. Total heap size = young generation size + Old generation size + persistent generation size. The permanent generation has a fixed size of 64m, so increasing the young generation will reduce the size of the old generation. This value has a significant impact on system performance. Sun officially recommends setting it to 3/8 of the entire heap.

** -xss128K: ** Sets the stack size for each thread. After JDK5.0, the stack size of each thread is 1M. Before JDK5.0, the stack size of each thread is 256K. The size of memory required by more applied threads is adjusted. Reducing this value generates more threads for the same physical memory. However, the operating system has a limit on the number of threads in a process, which cannot be generated indefinitely. The experience value is about 3000~5000.

  • java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

-xx :NewRatio=4: Sets the ratio of the young generation (including Eden and two Survivor zones) to the old generation (excluding persistent generation). If set to 4, the ratio of young generation to old generation is 1:4, and the young generation accounts for 1/5 of the entire stack

** -xx :SurvivorRatio=4: ** Sets the size ratio of Eden zone to Survivor zone in the young generation. If set to 4, the ratio of two Survivor zones to one Eden zone is 2:4, and one Survivor zone accounts for 1/6 of the whole young generation

-xx :MaxPermSize=16m: set the persistent generation size to 16m.

** -xx :MaxTenuringThreshold=0: ** Set the garbage maximum age. If set to 0, the young generation object passes through the Survivor zone and goes directly to the old generation. For the older generation of more applications, can improve efficiency. If you set this value to a large value, young generation objects will be copied multiple times in Survivor zones, increasing the lifetime of the object in the young generation and increasing the probability that it will be reclaimed in the young generation.

2. Collector selection

The JVM gives you three options: a serial collector, a parallel collector, and a concurrent collector, but serial collectors are only suitable for small amounts of data, so the choice here focuses on parallel and concurrent collectors. By default, JDK5.0 used a serial collector until now, and if you want to use another collector you need to add parameters at startup. After JDK5.0, the JVM makes a judgment based on the current system configuration.

  • java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20

** -xx :+UseParallelGC: ** Select garbage collector as parallel collector. This configuration is valid only for the young generation. In this configuration, the young generation uses concurrent collection, while the old generation still uses serial collection.

** -xx :ParallelGCThreads=20: ** Configure the number of threads for the parallel collector, i.e., how many threads are collecting garbage at the same time. This value is best configured to be equal to the number of processors.

  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC

-xx :+UseParallelOldGC: Sets the garbage collection mode for the aged generation to parallel collection. JDK6.0 supports parallel collection for older generations.

java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100

-xx :MaxGCPauseMillis=100: Sets the maximum time for each young generation garbage collection. If this time cannot be met, the JVM automatically adjusts the young generation size to meet this value.

  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicy

** -xx :+UseAdaptiveSizePolicy: ** When this option is set, the parallel collector automatically selects the size of the young generation and the corresponding ratio of Survivor regions to achieve the minimum corresponding time or collection frequency specified by the target system. This value is recommended to keep the parallel collector open when using it.

  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

-xx :+UseConcMarkSweepGC: Enables concurrent collection for the elderly user. After this was configured in the test, the -xx :NewRatio=4 configuration failed for unknown reasons. Therefore, it is best to set the size of the young generation with -xmn.

-xx :+UseParNewGC: sets concurrent collection for the young user. Can be used in conjunction with CMS collection. Above JDK5.0, the JVM will set itself based on the system configuration, so this value is no longer required.

  • java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection

* * – XX: CMSFullGCsBeforeCompaction: * * because of the concurrent collector wrong memory space is compressed, sorting, so run after a period of time will produce “fragments”, results in lower operation efficiency. This value sets the number of GC runs after which the memory space is compressed and collated.

* * – XX: + UseCMSCompactAtFullCollection: * * open compression of old generation. Performance may be affected, but fragmentation can be eliminated.

Auxiliary information The JVM provides a number of command-line arguments that print information for debugging. -xx :+PrintGC output form: [GC 118250K->113543K(130112K), 0.0094143 secs]

[Full GC 121376K->10414K, 0.0650971 secs]

-XX:+PrintGCDetails

Output form:

[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]

[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

-xx :+PrintGCTimeStamps -xx :+PrintGC: PrintGCTimeStamps can be used in combination with the above two

11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]

– XX: + PrintGCApplicationConcurrentTime: print before each garbage collection, the execution time of the procedure not interrupt. Can be mixed with the above

Output form:

Application time: 0.5291524 seconds

– XX: + PrintGCApplicationStoppedTime: print recycling program suspended during the period of time. Can be mixed with the above

Output form:

Total time for which application threads were stopped: 0.0468229 seconds

-xx :PrintHeapAtGC: displays detailed stack information before and after GC.

34.702: [GC {Heap before gc invocations=7:def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000), 0.0757599 secs]
Copy the code

** -xloggc :filename:** This command is used together with the preceding commands to record related log information to a file for analysis.

3. Common configurations

-xms: initial heap size -xmx: maximum heap size -xx :NewSize=n: Set the size of the young generation. -xx :NewRatio=n: Set the ratio of the young generation to the old generation. For example, if is 3, the ratio of the young generation to the old generation is 1:3, and the young generation accounts for 1/4 of the sum of the young generation and the old generation. -xx :SurvivorRatio=n: the ratio of Eden zone to two Survivor zones in the young generation. Notice that there are two Survivor zones. For example, 3 means Eden: Survivor= 3:2, and a Survivor zone accounts for 1/5 of the whole young generation

-xx :MaxPermSize=n: Set the persistent generation size

  • Collector setup

-xx :+UseSerialGC: Sets the serial collector. -xx :+UseParallelGC: sets the parallel collector. -xx :+UseParalledlOldGC: sets the parallel aged collector

-xx :+UseConcMarkSweepGC: Sets the concurrent collector

  • Garbage collection statistics

-XX:+PrintGC

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-Xloggc:filename

  • Parallel collector setup

-xx :ParallelGCThreads=n: Sets the number of cpus used by the parallel collector for collection. Collect the number of threads in parallel. -xx :MaxGCPauseMillis=n: Sets the maximum pause time for parallel collection. -xx :GCTimeRatio=n: sets the percentage of garbage collection time in the running time of the program. Formula for 1 / (1 + n)

  • Concurrent collector setup

-xx :+CMSIncrementalMode: set it to incremental mode. This mode applies to a single CPU.

-xx :ParallelGCThreads=n: Sets the number of cpus used when the collection mode of the young generation of the concurrent collector is parallel collection. Collect the number of threads in parallel.

Fourth, tuning summary

1, young generation size selection

** Response time first applications: ** Set as large as possible until it nears the minimum response time limit of the system (selected based on the actual situation). In this case, the frequency of young generation collection is the smallest. At the same time, reduce the number of objects that reach the aged generation. ** Throughput first applications: ** Set as large as possible, possibly up to Gbit. Since there is no response time requirement, garbage collection can be done in parallel and is generally suitable for applications with more than 8 cpus.

2, the size of the elderly generation selection

Response time first applications: Older generations use concurrent collectors, so their size needs to be carefully set, generally taking into account parameters such as concurrent session rate and session duration. If the heap is set too small, memory fragmentation, high recycle rates, and application pauses can result in traditional token cleanup. If the heap is large, it takes longer to collect. The optimal scheme generally needs to refer to the following data:

  • Concurrent garbage collection information

  • Number of concurrent collections for persistent generation

  • Traditional GC information

  • The proportion of time spent on recycling between the younger and older generations

Reducing the time spent by young and old generations generally improves application efficiency.

3. Throughput first applications

Typically throughput-first applications have a large young generation and a small old generation. The reason for this is that it is possible to recycle most of the short-term objects and reduce the medium-term objects, while the old generation is used to store the long-term living objects.

4. Fragmentation problems caused by smaller heaps

Because the concurrent collector of the older generation uses a mark-and-sweep algorithm, the heap is not compressed. When the collector collects, it merges adjacent Spaces so that they can be allocated to larger objects. However, when heap space is low, “fragmentation” can occur after running for a while, and if the concurrent collector cannot find enough space, the concurrent collector will stop and recycle using the traditional mark-and-sweep method. If there is a “fragments”, may need to have the following configuration: * * – XX: + UseCMSCompactAtFullCollection: * * use the concurrent collector, open to the older generation of compression. * * – XX: CMSFullGCsBeforeCompaction = 0: * * the above configuration under the condition of open, set how much time after Full GC, here to compress old generation.