SUN JVM의 Heap은 Old Generation(Tunured space라고도 불림)과 Young Generation으로 구성되어 있다. Young Generation은 다시 Eden과 두개의 Survivor Space(From Space, To Space)로 나누어 볼 수 있다.



Heap 영역의 동작 과정을 간략하게 살펴 본다면 보통 Object는 Eden에서 생성되며 Eden이 Full이 될 때 Live Object는 From Space로 Copy된다. 다시 Eden이 Full이 되면 From Space에서 To Space로 이동된다. 그리고 Eden이 다시 Full일 때, Object가 사용되거나 참조되고 있는 상태라면 Object는 Old Generation으로 이동하게 된다.



Object는 Eden에서 생성이 되고 Eden이 꽉 차게 되면 Memory copy가 발생한다고 하였다. 이러한 작업을 Minor Garbage collection이라 하고 Copy collenction이라고도 한다. Minor Collection시 Garbage Collector는 Eden의 Object를 검사하여 Reference가 없는 것 들은 제거하고 나머지 live Object는 From space가 꽉 찰 때까지 Eden에서 From Space로 이동하게 된다. 이러한 작업은 짧은 생애를 가질 수 밖에 없는 Object는 최대한 짧게 가지고 있겠다는 SUN  JVM의 특징을 그대로 나타내어 준다.

Eden이 다시 차오르면 From Space의 Live Object는 To Space로 이동한다. 그러나 이것은 논리적으로 그렇다는 것이고 실제로 JVM은 각 Minor collection이 발생할 때 마다 Survivor Space의 포인터를 유지하고 있다가 단순히 From Space에서 To Space로 변경해 주는 것이다. Eden이 다시 full이 되면 To Space에 있는 Live Object는 Old Generation으로 카피된다.

Minor Garbage Collection은 매우 빠르고 효율적이다. 소요시간은 Young Generation의 크기에 따라 다르지만 1초 미만이다. 또한 JVM Thread Processing를 멈추는 등의 부작용도 발생하지 않는다.

Young Generation이 모두 꽉차게 되면 Garbage Collector는 가용 메모리를 확보하기 위해 Major Garbage Collection을 수행한다. Major Garbage Collection은 Object들이 live상태로 있는지 여부를 파악하기 위해 모든 Thread의 수행을 잠시 동결시켜 살아있는 Object를 표시하고 Dead Object는 제거하여 Heap을 정리한다. 이러한 작업 때문에 Major Garbage Collection를 mark and sweep collection이라고도 한다. 이 Major Garbage Collection은 Thread를 잠시 멈추게 되고 Mark and Sweep작업을 위해 CPU에 부하를 가하게 되며 이러한 작업은 보통 Minor Garbage Collection에 비해 10배 이상의 시간을 사용하기 때문에 성능에 악영향을 주게 된다.

SUN  JVM은 앞서 언급한 대로 짧은 운명을 가지고 태어난 Object는 짧게, 그리고 장수할 운명을 지닌 Object는 오래도록 유지시키겠다는 의도를 지니고 있다고 하였다. SUN  JVM을 사용할 때는 이러한 의도를 잘 살려 주는 것이 결국 좋은 성능을 내는 것과 밀접한 관계가 있다할 수 있다. 즉 Short Live Object는 Old Generation으로 올라가기 전에 Young Generation에서 제거되게끔 하고 Long Lived Object의 경우 Old Generation에 상주시켜 상대적으로 아주 저렴한 Minor Garbage Collection만으로 Heap의 유지가 가능하게 유도하는 것이 좋다.

이를 위해서는 JVM의 Memory구성이 중요한데 Young Generation은 전체 Heap의 1/2보다 약간 적게 Survivor Space는 Young Generation의 1/8정도의 크기가 적당하다. 이렇게 Heap을 구성하기 위해서는 별도의 Option을 주어야 한다. JVM의 Default의 경우는 Young Generation이 작게 잡혀있기 때문에 Default를 사용하는 것은 권장하지 않는다. Young Generation이 작으면 short Live Object가 Old Generation으로 넘어갈 확률이 커지고 이는 결국 Major Garbage Collection의 발생확률이 높아지기 때문이다.


JAVA 메모리 대한 주요 옵션은 다음과 같다.

-XX:MaxNewSize=<Value> 
Young Generation의 최대 크기를 지정한다. Young Generation의 시작 크기는 NewSize 옵션에 의해 지정된다.

-XX:NewRatio=<Value>
Young Generation과 Old Generation의 비율을 결정한다. 예를 들어 이값이 2이면 Young:Old = 1:2 가 되고, Young Generation의 크기는 전체 Java Heap의 1/3이 된다.

-XX:NewSize=<Value>
Young Generation의 시작 크기를 지정한다. Young Generation의 크기는 NewSize 옵션(시작 크기)과 MaxNewSize 옵션(최대 크기)에 의해 결정된다.

-XX:PretenureSizeThreshold=<value>
일반적으로 Object는 Young Generation에 최초 저장된 후 시간이 흐름에 따라 Tenured Generation으로 Promotion된다. 하지만, Object의 크기가 Young Generation보다 큰 경우 JVM은 Old Generation에 Object를 직접 저장하기도 한다. PretenuredSizeThreshold 옵션을 이용하면 Young Generation을 거치지 않고 직접 Old Generation에 저장하게끔 할 수 있다. 가령 이 옵션의 값이 1048576(1M)이면, 1M 크기 이상의 오브젝트는 Old Generation에 바로 저장된다. 
큰 크기의 오브젝트를 Old Generation에 직접 저장함으로써 불필요한 Minor GC를 줄이고자 하는 목적으로 사용된다.

-Xms<size>
Java Heap의 최초 크기(Start Size)를 지정한다. Java Heap은 -Xms 옵션으로 지정한 크기로 시작하며 최대 -Xmx 옵션으로 지정한 크기만큼 커진다. Sun HotSpt JVM 계열에서는 최초 크기와 최대 크기를 동일하게 부여할 것을 권장한다. 크기의 동적인 변경에 의한 오버 헤드를 최소화하기 위해서이다.

-Xmx<size>
Java Heap의 최대 크기(Maximum Size)를 지정한다. Java Heap은 -Xms 옵션으로 지정한 크기로 시작하며 최대 -Xmx 옵션으로 지정한 크기만큼 커진다. Sun HotSpt JVM 계열에서는 최초 크기와 최대 크기를 동일하게 부여할 것을 권장한다. 크기의 동적인 변경에 의한 오버 헤드를 최소화하기 위해서이다.

** 모든 JAVA 옵션은 [http://wiki.ex-em.com/index.php/JVM_Options] 참조

출처 -  http://lyb1495.tistory.com/3








JVM maximum size (32bit/64bit)

First of all, let's have a global look about JVM Memory.
If we are using a 32bit OS, then the jvm can't have more than 4GB of RAM
Over this 4Gig, Os have their own needs. For exemple Windows needs 2GB for its kernel usage. So it left 2GB for our JVM.
But JVM implementation needs to have a continous memory region for the heap.

Here is the explanation :

The reason we need a contiguous memory region for the heap is that we have a bunch of side data structures that are indexed by (scaled) offsets from the start of the heap. For example, we track object reference updates with a "card mark array" that has one byte for each 512 bytes of heap. When we store a reference in the heap we have to mark the corresponding byte in the card mark array. We right shift the destination address of the store and use that to index the card mark array. Fun addressing arithmetic games you can't do in Java that you get to (have to :-) play in C++.
Usually we don't have trouble getting modest contiguous regions (up to about 1.5GB on Windohs, up to about 3.8GB on Solaris. YMMV.). On Windohs, the problem is mostly that there are some libraries that get loaded before the JVM starts up that break up the address space. Using the /3GB switch won't rebase those libraries, so they are still a problem for us.
We know how to make chunked heaps, but there would be some overhead to using them. We have more requests for faster storage management than we do for larger heaps in the 32-bit JVM. If you really want large heaps, switch to the 64-bit JVM. We still need contiguous memory, but it's much easier to get in a 64-bit address space.


So usually, JVM heap cannot be bigger than 1.2-1.6BG.

JVM memory overview

We could resume Java process heap with the following schema :



Java Heap & GC tuning

Java "Heap" is a continous memory region where all Objects data will be stored (by data, we mean instance of class, primitive and references). It's a big part of the process heap.
It can be configured using the following parameters :
  • -Xmx : max heap size (ex: -Xmx1024)
  • -Xms : min heap size. Having -Xms = 1.8GB (32bit) can be bad, because you don't let memory for anything else.
  • -Xmn : the size of the heap for the young generation
    Young generation represents all the objects which have a short life of time. Young generation objects are in a specific location into the heap, where the garbage collector will pass often. All new objects are created into the young generation region (called "eden"). When an object survive is still "alive" after more than 2-3 gc cleaning, then it will be swap has an "old generation" : they are "survivor" .
    Good size is 33%
  • -XX:NewRatio : the same as Wmn, but using a % (dynamic fs static -Xmn option). -XX:NewRatio=3 means that the ratio between the old and young generation is 1:3
  • -XX:NewSize - Size of the young generation at JVM init. Calculated automatically if you specify -XX:NewRatio
  • -XX:MaxNewSize - The largest size the young generation can grow to (unlimited if this value is not specified at command line)
  • -XX:SurvivorRatio : "old generation" called tenured generation, ratio, in %. For example, -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden to be 1:6 (eden is where new objects are created)
  • -XX:MinHeapFreeRatio: default is 40%. JVM will allocate memory to always have as minimum 40% of free memory. When -Xmx = -Xms, it's useless.
  • -XX:MaxHeapFreeRatio: default is 70%. The same as Min, to avoid unecessary memory allocation.

More informationabout Sun HotSpot GC tuning here and general gc tuning here 
At this point, we get a problem. In a multithread application, object can be created at the same time. Thread could try to write data into the same heap location at the same time.
To avoid this problem, we allow each thread to have a private piece into the eden space.
jdk 1.5> uses dynamic sizing algorithm, specific for each thread. (otherwise, parameter such as -XX:UseTLAB or -XX:TLABSize can be used to tune this parameter)

And EveryThing Else...

Every thing else is...
  • Permanent Space : It's the third part of the memory. Here are stored classes, methods etc.
    • -XX:PermSize: initial value
    • -XX:MaxPermSize: max value
  • Code generation : Converted byte code into native code. Shouldn't cause troubles.
  • Socket Buffer (contains the 2 buffers for each sockets: receive/send)
  • Thread Stacks: Each thread has its own stack. It makes possible to get your methods thread-safe.
    • -Xss: change the space of a thread stack. 2048 could be a write value. It can cause a java.lang.stackOverFlow Error
    • If you get a "java.lang.OutOfMemoryError : unable to create new native Thread, you can decrease -Xss or decrease the java heap using -Xmx/-Xms (to increase the thread stack space)
  • Direct memory space (ability to let Java developers map memory outside the Java Object Heap. Can be adjusted using -XX:MaxDirectMemory=
  • JNI Code, if you use it
  • Garbage Collection (the GC has its own thread/informations)

A nice gotcha...

Major collection don't run until tenured is full.
This mean that using -Xmx1024, current heap could be 750MB with 500MB of "dead" object. If the JVM is idle, it could stay like that during a very long time => wasting 500MB or RAM for an idle JVM ! 

More informations about GC memory & monitoring here
You should also read this awesome slideshare from Filip Hanik, Covalent (gotcha, etc... most of this informations come from this slides)



source - http://www.avricot.com/blog/?post/2010/05/03/Get-started-with-java-JVM-memory-(heap%2C-stack%2C-xss-xms-xmx-xmn...)






Java HotSpot VM Options


At a Glance 

Core 

Database 

Desktop 

Accessibility 

Security 

Tools 

Web Services 

Real-Time 
 

Overview

Basic 

CORBA 

HotSpot VM 

JNDI 

Mntr-Mgmt 

Tools APIs 

XML 


Please note that this page only applies to JDK 7 and earlier releases. For JDK 8 please see the WindowsSolarisLinux and Mac OS X reference pages.


This document provides information on typical command-line options and environment variables that can affect the performance characteristics of the Java HotSpot Virtual Machine. Unless otherwise noted, all information in this document pertains to both the Java HotSpot Client VM and the Java HotSpot Server VM.

Categories of Java HotSpot VM Options

  

Standard options recognized by the Java HotSpot VM are described on the Java Application Launcher reference pages for Windows and Solaris & Linux. This document deals exclusively with non-standard options recognized by the Java HotSpot VM:

  • Options that begin with -X are non-standard (not guaranteed to be supported on all VM implementations), and are subject to change without notice in subsequent releases of the JDK.
  • Options that are specified with -XX are not stable and are subject to change without notice.

Users of JDKs older than 1.3.0 who wish to port to a Java HotSpot VM, should see Java HotSpot Equivalents of Exact VM flags.

Some Useful -XX Options

  

Default values are listed for Java SE 6 for Solaris Sparc with -server. Some options may vary per architecture/OS/JVM version. Platforms with a differing default value are listed in the description.

  • Boolean options are turned on with -XX:+<option> and turned off with -XX:-<option>.Disa
  • Numeric options are set with -XX:<option>=<number>. Numbers can include 'm' or 'M' for megabytes, 'k' or 'K' for kilobytes, and 'g' or 'G' for gigabytes (for example, 32k is the same as 32768).
  • String options are set with -XX:<option>=<string>, are usually used to specify a file, a path, or a list of commands

Flags marked as manageable are dynamically writeable through the JDK management interface (com.sun.management.HotSpotDiagnosticMXBean API) and also through JConsole. In Monitoring and Managing Java SE 6 Platform Applications, Figure 3 shows an example. The manageable flags can also be set through jinfo -flag

The options below are loosely grouped into categories.

  

Behavioral Options


Option and Default ValueDescription
-XX:-AllowUserSignalHandlersDo not complain if the application installs signal handlers. (Relevant to Solaris and Linux only.)
-XX:AltStackSize=16384Alternate signal stack size (in Kbytes). (Relevant to Solaris only, removed from 5.0.)
-XX:-DisableExplicitGCBy default calls to System.gc() are enabled (-XX:-DisableExplicitGC). Use -XX:+DisableExplicitGC to disable calls to System.gc(). Note that the JVM still performs garbage collection when necessary.
-XX:+FailOverToOldVerifierFail over to old verifier when the new type checker fails. (Introduced in 6.)
-XX:+HandlePromotionFailureThe youngest generation collection does not require a guarantee of full promotion of all live objects. (Introduced in 1.4.2 update 11) [5.0 and earlier: false.]
-XX:+MaxFDLimitBump the number of file descriptors to max. (Relevant  to Solaris only.)
-XX:PreBlockSpin=10Spin count variable for use with -XX:+UseSpinning. Controls the maximum spin iterations allowed before entering operating system thread synchronization code. (Introduced in 1.4.2.)
-XX:-RelaxAccessControlCheckRelax the access control checks in the verifier. (Introduced in 6.)
-XX:+ScavengeBeforeFullGCDo young generation GC prior to a full GC. (Introduced in 1.4.1.)
-XX:+UseAltSigsUse alternate signals instead of SIGUSR1 and SIGUSR2 for VM internal signals. (Introduced in 1.3.1 update 9, 1.4.1. Relevant to Solaris only.)
-XX:+UseBoundThreadsBind user level threads to kernel threads. (Relevant to Solaris only.)
-XX:-UseConcMarkSweepGCUse concurrent mark-sweep collection for the old generation. (Introduced in 1.4.1)
-XX:+UseGCOverheadLimitUse a policy that limits the proportion of the VM's time that is spent in GC before an OutOfMemory error is thrown. (Introduced in 6.)
-XX:+UseLWPSynchronizationUse LWP-based instead of thread based synchronization. (Introduced in 1.4.0. Relevant to Solaris only.)
-XX:-UseParallelGCUse parallel garbage collection for scavenges. (Introduced in 1.4.1)
-XX:-UseParallelOldGCUse parallel garbage collection for the full collections. Enabling this option automatically sets -XX:+UseParallelGC. (Introduced in 5.0 update 6.)
-XX:-UseSerialGCUse serial garbage collection. (Introduced in 5.0.)
-XX:-UseSpinningEnable naive spinning on Java monitor before entering operating system thread synchronizaton code. (Relevant to 1.4.2 and 5.0 only.) [1.4.2, multi-processor Windows platforms: true]
-XX:+UseTLABUse thread-local object allocation (Introduced in 1.4.0, known as UseTLE prior to that.) [1.4.2 and earlier, x86 or with -client: false]
-XX:+UseSplitVerifierUse the new type checker with StackMapTable attributes. (Introduced in 5.0.)[5.0: false]
-XX:+UseThreadPrioritiesUse native thread priorities.
-XX:+UseVMInterruptibleIOThread interrupt before or with EINTR for I/O operations results in OS_INTRPT. (Introduced in 6. Relevant to Solaris only.)


Back to Options 
  

Garbage First (G1) Garbage Collection Options


Option and Default ValueDescription
-XX:+UseG1GCUse the Garbage First (G1) Collector
-XX:MaxGCPauseMillis=nSets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it.
-XX:InitiatingHeapOccupancyPercent=nPercentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations (e.g., G1). A value of 0 denotes 'do constant GC cycles'. The default value is 45.
-XX:NewRatio=nRatio of old/new generation sizes. The default value is 2.
-XX:SurvivorRatio=nRatio of eden/survivor space size. The default value is 8.
-XX:MaxTenuringThreshold=nMaximum value for tenuring threshold. The default value is 15.
-XX:ParallelGCThreads=nSets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running.
-XX:ConcGCThreads=nNumber of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running.
-XX:G1ReservePercent=nSets the amount of heap that is reserved as a false ceiling to reduce the possibility of promotion failure. The default value is 10.
-XX:G1HeapRegionSize=nWith G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb.


Back to Options 
 

Performance Options


Option and Default ValueDescription
-XX:+AggressiveOptsTurn on point performance compiler optimizations that are expected to be default in upcoming releases. (Introduced in 5.0 update 6.)
-XX:CompileThreshold=10000Number of method invocations/branches before compiling [-client: 1,500]
-XX:LargePageSizeInBytes=4mSets the large page size used for the Java heap. (Introduced in 1.4.0 update 1.) [amd64: 2m.]
-XX:MaxHeapFreeRatio=70Maximum percentage of heap free after GC to avoid shrinking.
-XX:MaxNewSize=sizeMaximum size of new generation (in bytes). Since 1.4, MaxNewSize is computed as a function of NewRatio. [1.3.1 Sparc: 32m; 1.3.1 x86: 2.5m.]
-XX:MaxPermSize=64mSize of the Permanent Generation.  [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]
-XX:MinHeapFreeRatio=40Minimum percentage of heap free after GC to avoid expansion.
-XX:NewRatio=2Ratio of old/new generation sizes. [Sparc -client: 8; x86 -server: 8; x86 -client: 12.]-client: 4 (1.3) 8 (1.3.1+), x86: 12]
-XX:NewSize=2mDefault size of new generation (in bytes) [5.0 and newer: 64 bit VMs are scaled 30% larger; x86: 1m; x86, 5.0 and older: 640k]
-XX:ReservedCodeCacheSize=32mReserved code cache size (in bytes) - maximum code cache size. [Solaris 64-bit, amd64, and -server x86: 2048m; in 1.5.0_06 and earlier, Solaris 64-bit and amd64: 1024m.]
-XX:SurvivorRatio=8Ratio of eden/survivor space size [Solaris amd64: 6; Sparc in 1.3.1: 25; other Solaris platforms in 5.0 and earlier: 32]
-XX:TargetSurvivorRatio=50Desired percentage of survivor space used after scavenge.
-XX:ThreadStackSize=512Thread Stack Size (in Kbytes). (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
-XX:+UseBiasedLockingEnable biased locking. For more details, see thistuning example. (Introduced in 5.0 update 6.) [5.0: false]
-XX:+UseFastAccessorMethodsUse optimized versions of Get<Primitive>Field.
-XX:-UseISMUse Intimate Shared Memory. [Not accepted for non-Solaris platforms.] For details, see Intimate Shared Memory.
-XX:+UseLargePagesUse large page memory. (Introduced in 5.0 update 5.) For details, see Java Support for Large Memory Pages.
-XX:+UseMPSSUse Multiple Page Size Support w/4mb pages for the heap. Do not use with ISM as this replaces the need for ISM. (Introduced in 1.4.0 update 1, Relevant to Solaris 9 and newer.) [1.4.1 and earlier: false]
-XX:+UseStringCacheEnables caching of commonly allocated strings.
 
-XX:AllocatePrefetchLines=1Number of cache lines to load after the last object allocation using prefetch instructions generated in JIT compiled code. Default values are 1 if the last allocated object was an instance and 3 if it was an array. 
 
-XX:AllocatePrefetchStyle=1Generated code style for prefetch instructions.
0 - no prefetch instructions are generate*d*,
1 - execute prefetch instructions after each allocation,
2 - use TLAB allocation watermark pointer to gate when prefetch instructions are executed.
 
-XX:+UseCompressedStringsUse a byte[] for Strings which can be represented as pure ASCII. (Introduced in Java 6 Update 21 Performance Release) 
 
-XX:+OptimizeStringConcatOptimize String concatenation operations where possible. (Introduced in Java 6 Update 20) 
 


Back to Options 
  

Debugging Options


Option and Default ValueDescription
-XX:-CITimePrints time spent in JIT Compiler. (Introduced in 1.4.0.)
-XX:ErrorFile=./hs_err_pid<pid>.logIf an error occurs, save the error data to this file. (Introduced in 6.)
-XX:-ExtendedDTraceProbesEnable performance-impacting dtrace probes. (Introduced in 6. Relevant to Solaris only.)
-XX:HeapDumpPath=./java_pid<pid>.hprofPath to directory or filename for heap dump.Manageable. (Introduced in 1.4.2 update 12, 5.0 update 7.)
-XX:-HeapDumpOnOutOfMemoryErrorDump heap to file when java.lang.OutOfMemoryError is thrown. Manageable. (Introduced in 1.4.2 update 12, 5.0 update 7.)
-XX:OnError="<cmd args>;<cmd args>"Run user-defined commands on fatal error. (Introduced in 1.4.2 update 9.)
-XX:OnOutOfMemoryError="<cmd args>; 
<cmd args>"
Run user-defined commands when an OutOfMemoryError is first thrown. (Introduced in 1.4.2 update 12, 6)
-XX:-PrintClassHistogramPrint a histogram of class instances on Ctrl-Break.Manageable. (Introduced in 1.4.2.) The jmap -histocommand provides equivalent functionality.
-XX:-PrintConcurrentLocksPrint java.util.concurrent locks in Ctrl-Break thread dump. Manageable. (Introduced in 6.) The jstack -lcommand provides equivalent functionality.
-XX:-PrintCommandLineFlagsPrint flags that appeared on the command line. (Introduced in 5.0.)
-XX:-PrintCompilationPrint message when a method is compiled.
-XX:-PrintGCPrint messages at garbage collection. Manageable.
-XX:-PrintGCDetailsPrint more details at garbage collection.Manageable. (Introduced in 1.4.0.)
-XX:-PrintGCTimeStampsPrint timestamps at garbage collection. Manageable(Introduced in 1.4.0.)
-XX:-PrintTenuringDistributionPrint tenuring age information.
-XX:-PrintAdaptiveSizePolicyEnables printing of information about adaptive generation sizing.
-XX:-TraceClassLoadingTrace loading of classes.
-XX:-TraceClassLoadingPreorderTrace all classes loaded in order referenced (not loaded). (Introduced in 1.4.2.)
-XX:-TraceClassResolutionTrace constant pool resolutions. (Introduced in 1.4.2.)
-XX:-TraceClassUnloadingTrace unloading of classes.
-XX:-TraceLoaderConstraintsTrace recording of loader constraints. (Introduced in 6.)
-XX:+PerfDataSaveToFileSaves jvmstat binary data on exit.
-XX:ParallelGCThreads=nSets the number of garbage collection threads in the young and old parallel garbage collectors. The default value varies with the platform on which the JVM is running.
-XX:+UseCompressedOopsEnables the use of compressed pointers (object references represented as 32 bit offsets instead of 64-bit pointers) for optimized 64-bit performance with Java heap sizes less than 32gb.
-XX:+AlwaysPreTouchPre-touch the Java heap during JVM initialization. Every page of the heap is thus demand-zeroed during initialization rather than incrementally during application execution.
-XX:AllocatePrefetchDistance=nSets the prefetch distance for object allocation. Memory about to be written with the value of new objects is prefetched into cache at this distance (in bytes) beyond the address of the last allocated object. Each Java thread has its own allocation point. The default value varies with the platform on which the JVM is running.
-XX:InlineSmallCode=nInline a previously compiled method only if its generated native code size is less than this. The default value varies with the platform on which the JVM is running.
-XX:MaxInlineSize=35Maximum bytecode size of a method to be inlined.
-XX:FreqInlineSize=nMaximum bytecode size of a frequently executed method to be inlined. The default value varies with the platform on which the JVM is running.
-XX:LoopUnrollLimit=nUnroll loop bodies with server compiler intermediate representation node count less than this value. The limit used by the server compiler is a function of this value, not the actual value. The default value varies with the platform on which the JVM is running.
-XX:InitialTenuringThreshold=7Sets the initial tenuring threshold for use in adaptive GC sizing in the parallel young collector. The tenuring threshold is the number of times an object survives a young collection before being promoted to the old, or tenured, generation.
-XX:MaxTenuringThreshold=nSets the maximum tenuring threshold for use in adaptive GC sizing. The current largest value is 15. The default value is 15 for the parallel collector and is 4 for CMS.
-Xloggc:<filename>Log GC verbose output to specified file. The verbose output is controlled by the normal verbose GC flags.
-XX:-UseGCLogFileRotationEnabled GC log rotation, requires -Xloggc.
-XX:NumberOfGClogFiles=1Set the number of files to use when rotating logs, must be >= 1. The rotated log files will use the following naming scheme, <filename>.0, <filename>.1, ..., <filename>.n-1.
-XX:GCLogFileSize=8KThe size of the log file at which point the log will be rotated, must be >= 8K.


Back to Options



source - http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html







JVM(Java Virtual Machine) 성능 조정


Java 프로세스인 Application Server는 실행하고 서버에서 실행하는 Java 응용프로그램을 지원하기 위해 JVM(Java Virtual Machine)이 필요합니다. Application Server 구성의 일부로서 JVM의 시스템 사용을 개선시키는 설정을 미세 조정할 수 있습니다.

이 타스크 정보

JVM은 Java 기반 응용프로그램을 위한 런타임 실행 환경을 제공합니다. WebSphere Application Server는 JVM 런타임 환경과 Java 기반 서버 런타임의 조합입니다. 다른 JVM 프로바이더의 JVM에서 실행할 수 있습니다. 사용자의 Application Server가 실행 중인 JVM 프로바이더를 판별하려면 WebSphere Application Server app_server_root/java/bin 디렉토리에서 java –fullversion 명령을 발행하십시오. 또한 서버 중 하나에서 SystemOut.log를 검사할 수도 있습니다. Application Server가 시작할 때 WebSphere Application Server는 JVM 프로바이더 정보를 포함한 JVM에 관한 정보를 이 로그 파일에 기록합니다.

JVM 조정 Perspective에서 두 가지 기본 유형의 JVM이 있습니다.
  • IBM JVM
  • Solaris의 Sun HotSpot JVM 및 HP의 HP-UX용 JVM을 포함한 Sun HotSpot 기반 JVM
JVM 조정이 JVM 프로바이더에 따라 다르지만 일반 조정 개념은 모든 JVM에 적용됩니다. 일반 개념은 다음을 포함합니다.
  • 컴파일러 조정. 모든 JVM은 JIT(Just In Time) 컴파일러를 사용하여 서버 런타임 중에 Java 바이트 코드를 기본 명령어로 컴파일합니다.
  • Java 메모리 또는 힙 조정. JVM 메모리 관리 기능 또는 가비지 콜렉션이 JVM 성능 향상을 위한 가장 큰 기회 중 하나를 제공합니다.
  • 클래스 로딩 조정.

프로시저

  • 시작 성능 및 런타임 성능을 최적화하십시오.

    일부 환경에서는 런타임 성능보다 WebSphere Application Server의 시작 성능을 최적화하는 것이 더 중요합니다. 다른 환경에서는 런타임 환경을 최적화하는 것이 더 중요합니다. 기본적으로 IBM JVM은 런타임 환경을 위해 최적화되는 반면 HotSpot 기반 JVM은 시작 성능을 위해 최적화됩니다.

    Java JIT 컴파일러는 시작 또는 런타임 성능이 최적화되는지 여부에 큰 영향을 줍니다. 컴파일러가 사용하는 초기 최적화 레벨은 클래스 메소드를 컴파일하는 데 걸리는 시간과 서버를 시작하는 데 걸리는 시간에 영향을 줍니다. 더 빠른 시작을 위해 컴파일러가 사용하는 초기 최적화 레벨을 줄일 수 있습니다. 이는 클래스 메소드가 이제 더 낮은 최적화 레벨에서 컴파일되기 때문에 응용프로그램의 런타임 성능이 저하될 수 있음을 의미합니다.

    재컴파일이 더 좋은 성능을 제공할 수 있다는 컴파일러의 판단에 따라서 컴파일러가 런타임 실행 중에 클래스 메소드를 다시 컴파일할 수 있기 때문에 특정한 런타임 성능 영향 명령문을 규정하기는 어렵습니다. 궁극적으로 응용프로그램의 지속 기간이 발생하는 런타임 저하의 양에 대한 주요 영향입니다. 짧게 실행하는 응용프로그램은 메소드가 다시 컴파일되는 확률이 더 높습니다. 장기간 실행하는 응용프로그램은 메소드가 다시 컴파일될 가능성이 작습니다. IBM JVM의 기본 설정은 초기 컴파일에 대해 높은 최적화 레벨을 사용합니다. 이 동작을 변경해야 하는 경우 다음 IBM JVM 옵션을 사용할 수 있습니다.

    -Xquickstart

    이 설정은 IBM JVM이 클래스 메소드 컴파일에 대해 더 낮은 최적화 레벨을 사용하는 방법에 영향을 주며, 이는 런타임 성능을 희생하는 대신 더 빠른 서버 시작을 제공합니다. 이 매개변수가 지정되지 않는 경우 IBM JVM은 기본적으로 컴파일에 대해 높은 초기 최적화 레벨로 시작합니다. 이 설정은 서버 시작은 더 느린 대신 더 빠른 런타임 성능을 제공합니다.

    기본값:높은 초기 컴파일러 최적화 레벨
    권장:높은 초기 컴파일러 최적화 레벨
    사용법:-Xquickstart는 더 빠른 서버 시작 시간을 제공할 수 있습니다.

    Sun의 Hotspot 기술을 기초로 하는 JVM은 초기에 낮은 최적화 레벨에서 클래스 메소드를 컴파일합니다. 다음 JVM 옵션을 사용하여 이 동작을 변경하십시오.

    -server

    Sun의 Hotspot 기술을 기초로 하는 JVM은 초기에 낮은 최적화 레벨에서 클래스 메소드를 컴파일합니다. 이들 JVM은 단순 컴파일러 및 최적화 JIT 컴파일러를 사용합니다. 일반적으로 단순 JIT 컴파일러가 사용됩니다. 그러나 이 옵션을 사용하여 최적화 컴파일러를 사용되는 컴파일러로 만들 수 있습니다. 이 변경은 서버의 성능을 크게 증가시키지만 최적화 컴파일러가 사용될 때 서버가 시작하는 데 더 오래 걸립니다.

    기본값:단순 컴파일러
    권장:최적화 컴파일러
    사용법:-server가 최적화 컴파일러를 사용 가능하게 합니다.
  • 힙 크기를 설정하십시오. 다음 명령행 매개변수가 힙 크기 설정에 유용합니다.
    • -Xms

      이 설정은 Java 힙의 초기 크기를 제어합니다. 이 매개변수를 적절하게 조정하면 가비지 콜렉션의 오버헤드를 줄여서 서버 응답 시간 및 처리량을 개선합니다. 일부 응용프로그램의 경우, 이 옵션에 대한 기본 설정이 너무 낮아서 사소한 가비지 콜렉션의 수가 높아질 수 있습니다.

      기본값:256 MB
      권장:워크로드에 특정하지만, 기본값보다 높습니다.
      사용법:-Xms256m은 초기 힙 크기를 256MB로 설정합니다.
    • -Xmx

      이 설정은 Java 힙의 최대 크기를 제어합니다. 이 매개변수를 적절하게 조정하면 가비지 콜렉션의 오버헤드를 줄여서 서버 응답 시간 및 처리량을 개선할 수 있습니다. 일부 응용프로그램의 경우, 이 옵션에 대한 기본 설정이 너무 낮아서 사소한 가비지 콜렉션의 수가 높아질 수 있습니다.

      기본값:512 MB
      권장:워크로드에 특정하지만, 기본값보다 높습니다.
      사용법:-Xmx512m은 최대 힙 크기를 512MB로 설정합니다.
    • -Xlp

      이 설정은 IBM JVM과 함께 사용되어 대형 페이지를 사용하는 힙을 할당할 수 있습니다. 그러나 이 설정을 사용하는 경우 운영 체제가 대형 페이지를 지원하도록 구성되어야 합니다. 대형 페이지를 사용하면 힙 메모리를 추적하기 위해 필요한 CPU 오버헤드를 줄일 수 있으며 또한 더 큰 힙의 작성을 허용할 수 있습니다.

      운영 체제 조정에 대한 자세한 정보 운영 체제 성능 조정 의 내용을 참조하십시오.

    사용자가 힙에 대해 지정해야 하는 크기는 시간에 따른 힙 사용량에 따라 다릅니다. 힙 크기가 자주 변경되는 경우에는 Xms 및 Xmx 매개변수에 동일한 값을 지정하는 경우 성능을 향상시킬 수 있습니다.

  • IBM JVM의 가비지 콜렉터를 조정하십시오.

    Java -X 옵션을 사용하여 메모리 옵션의 목록을 참조하십시오.

    • -Xgcpolicy

      gcpolicy를 optthruput으로 설정하면 동시 마크가 사용 불가능합니다. 오류가 있는 응용프로그램 응답 시간으로 표시되는 일시정지 시간 문제점이 있지 않은 경우 이 옵션을 사용하여 최상의 처리량을 가져와야 합니다. gcpolicy를 optavgpause로 설정하면 동시 표시가 기본값과 함께 사용 가능하게 됩니다. 이 설정은 정상 가비지 콜렉션에 의해 유발되는 오류가 있는 응용프로그램 응답 시간을 완화시킵니다. 그러나 이 옵션은 전체 처리량을 줄일 수 있습니다.

      기본값:optthruput
      권장:optthruput
      사용법:Xgcpolicy:optthruput
    • -Xnoclassgc

      기본적으로 JVM은 클래스의 활동하는 인스턴스가 없을 때 메모리에서 해당 클래스를 로드 해제하지만, 이는 성능을 저하시킬 수 있습니다. 클래스 가비지 콜렉션을 끄면 동일한 클래스를 여러 번 로드 및 로드 해제하는 오버헤드를 제거합니다.

      클래스가 더 이상 필요없는 경우 클래스가 힙에서 차지하는 공간은 일반적으로 새 오브젝트의 작성을 위해 사용됩니다. 그러나 클래스의 새 인스턴스를 작성하여 요청을 처리하는 응용프로그램이 있고 해당 응용프로그램에 대한 요청이 임의 시간에 오는 경우, 이전 요청자가 완료될 때 다음 요청이 나타날 때만 클래스를 다시 인스턴스화하기 위해 정상 클래스 가비지 콜렉션이 클래스가 차지했던 힙 공간을 사용 가능하게 해서 이 클래스를 지우는 것이 가능합니다. 이 상황에서는 이 옵션을 사용하여 클래스의 가비지 콜렉션을 사용하지 않을 수 있습니다.

      기본값:클래스 가비지 콜렉션 사용 가능
      권장:클래스 가비지 콜렉션 사용 불가능
      사용법:Xnoclassgc가 클래스 가비지 콜렉션을 사용 불가능하게 합니다.
    추가 정보에 대해서는 다음 DeveloperWorks 항목을 확인하십시오.
  •  Sun JVM의 가비지 콜렉터를 조정하십시오.

    Solaris 플랫폼에서 WebSphere Application Server는 IBM JVM이 아니라 Sun Hotspot JVM에서 실행합니다. 성능 최적화 기능을 이용하기 위해서는 Sun JVM과 함께 올바른 조정 매개변수를 사용하는 것이 중요합니다.

    Sun HotSpot JVM은 최적 성능을 달성하기 위해 세대별 가비지 콜렉션에 의존합니다. 다음 명령행 매개변수가 가비지 콜렉션 조정에 유용합니다.

    • -XX:SurvivorRatio

      Java 힙은 예전에 생성된(old) 즉, 오브젝트용 섹션과 최근에 생성된(young) 오브젝트용 섹션으로 나뉘어집니다. 최근에 생선된(young) 오브젝트용 섹션은 다시 새 오브젝트가 할당되는 섹션(eden)과 여전히 사용 중인 새 오브젝트가 이전 오브젝트로 승격되기 전에 처음 몇 번의 가비지 콜렉션에서 살아남는 섹션(감독자 공간)으로 나뉘어집니다. 감독자 비율은 힙의 최근에 생선된(young) 오브젝트 섹션에서 감독자 공간에 대한 eden의 비율입니다. 이 설정을 늘리면 높은 오브젝트 작성 및 낮은 오브젝트 보존을 갖는 응용프로그램에 대해 JVM을 최적화합니다. WebSphere Application Server가 다른 응용프로그램보다 더 많은 중간 및 오래 활동하는 오브젝트를 생성하므로, 이 설정은 기본값보다 낮아야 합니다.

      기본값:32
      권장:16
      사용법:-XX:SurvivorRatio=16
    • -XX:PermSize

      영구 생성을 위해 예약되는 힙의 섹션은 JVM에 대한 모든 반사 데이터를 보유합니다. 이 크기는 많은 클래스를 동적으로 로드하고 로드 해제하는 응용프로그램의 성능을 최적화하기 위해 늘려야 합니다. 이 설정을 값 128MB로 설정하면 힙의 이 파트를 증가시키는 오버헤드를 제거합니다.

      권장:128 MB
      사용법:XX:PermSize=128m은 perm 크기를 128MB로 설정합니다.
    • -Xmn

      이 설정은 젋음 세대가 힙에서 소비하도록 허용되는 공간을 제어합니다. 이 매개변수를 적절하게 조정하면 가비지 콜렉션의 오버헤드를 줄여서 서버 응답 시간 및 처리량을 개선할 수 있습니다. 이 옵션에 대한 기본 설정은 일반적으로 너무 낮아서 사소한 가비지 콜렉션의 수를 높게 만듭니다. 이 설정을 너무 높게 설정하면 JVM이 주요(또는 전체) 가비지 콜렉션만 수행하게 만들 수 있습니다. 이들은 대개 몇 초가 걸리며 서버의 전체 성능에 극히 불리합니다. 이 상황을 피하기 위해 이 설정을 전체 힙 크기의 절반 이하로 유지해야 합니다.

      기본값:2228224 바이트
      권장:대략 총 힙 크기의 1/4
      사용법:-Xmn256m은 크기를 256MB로 설정합니다.
    • -Xnoclassgc

      기본적으로 JVM은 클래스의 활동하는 인스턴스가 없을 때 메모리에서 해당 클래스를 로드 해제하지만, 이는 성능을 저하시킬 수 있습니다. 클래스 가비지 콜렉션을 끄면 동일한 클래스를 여러 번 로드 및 로드 해제하는 오버헤드를 제거합니다.

      클래스가 더 이상 필요없는 경우 클래스가 힙에서 차지하는 공간은 일반적으로 새 오브젝트의 작성을 위해 사용됩니다. 그러나 클래스의 새 인스턴스를 작성하여 요청을 처리하는 응용프로그램이 있고 해당 응용프로그램에 대한 요청이 임의 시간에 오는 경우, 이전 요청자가 완료될 때 다음 요청이 나타날 때만 클래스를 다시 인스턴스화하기 위해 정상 클래스 가비지 콜렉션이 클래스가 차지했던 힙 공간을 사용 가능하게 해서 이 클래스를 지우는 것이 가능합니다. 이 상황에서는 이 옵션을 사용하여 클래스의 가비지 콜렉션을 사용하지 않을 수 있습니다.

      기본값:클래스 가비지 콜렉션 사용 가능
      권장:클래스 가비지 콜렉션 사용 불가능
      사용법:Xnoclassgc가 클래스 가비지 콜렉션을 사용 불가능하게 합니다.

    Sun JVM 조정에 대한 추가 정보는 Performance Documentation for the Java HotSpot VM를 확인하십시오.

  •  HP JVM의 가비지 콜렉터를 조정하십시오.

    HP JVM은 최적 성능을 달성하기 위해 세대별 가비지 콜렉션에 의존합니다. 다음 명령행 매개변수가 가비지 콜렉션 조정에 유용합니다.

    • -Xoptgc

      이 설정은 수명이 짧은 많은 오브젝트를 갖는 응용프로그램에 대해 JVM을 최적화합니다. 이 매개변수가 지정되지 않으면 JVM은 대개 주요(전체) 가비지 콜렉션을 수행합니다. 전체 가비지 콜렉션은 수 초가 걸릴 수 있으며 서버 성능을 크게 저하시킬 수 있습니다.

      기본값:off
      권장:on
      사용법:-Xoptgc는 최적화된 가비지 콜렉션을 사용 가능하게 합니다.
    • -XX:SurvivorRatio

      Java 힙은 예전에 생성된(old) 즉, 오브젝트용 섹션과 최근에 생성된(young) 오브젝트용 섹션으로 나뉘어집니다. 최근에 생선된(young) 오브젝트용 섹션은 다시 새 오브젝트가 할당되는 섹션(eden)과 여전히 사용 중인 새 오브젝트가 이전 오브젝트로 승격되기 전에 처음 몇 번의 가비지 콜렉션에서 살아남는 섹션(감독자 공간)으로 나뉘어집니다. 감독자 비율은 힙의 최근에 생선된(young) 오브젝트 섹션에서 감독자 공간에 대한 eden의 비율입니다. 이 설정을 늘리면 높은 오브젝트 작성 및 낮은 오브젝트 보존을 갖는 응용프로그램에 대해 JVM을 최적화합니다. WebSphere Application Server가 다른 응용프로그램보다 더 많은 중간 및 오래 활동하는 오브젝트를 생성하므로, 이 설정은 기본값보다 낮아야 합니다.

      기본값:32
      권장:16
      사용법:-XX:SurvivorRatio=16
    • -XX:PermSize

      영구 생성을 위해 예약되는 힙의 섹션은 JVM에 대한 모든 반사 데이터를 보유합니다. 이 크기는 많은 클래스를 동적으로 로드하고 로드 해제하는 응용프로그램의 성능을 최적화하기 위해 늘려야 합니다. 128MB의 값을 지정하면 힙의 이 파트를 증가시키는 오버헤드를 제거합니다.

      기본값:0
      권장:128MB
      사용법:-XX:PermSize=128m은 PermSize를 128MB로 설정합니다.
    • -XX:+ForceMmapReserved

      기본적으로 Java 힙은 "지연 스왑" 할당됩니다. 이는 필요할 때 메모리 페이지를 할당하여 스왑 공간을 절약하지만 또한 4KB 페이지의 사용을 강제합니다. 이 메모리 할당은 대형 힙 시스템에서 힙을 수십만개의 페이지에 분산시킬 수 있습니다. 이 명령은 "지연 스왑"을 사용 불가능하게 하고 운영 체제가 더 큰 메모리 페이지를 사용할 수 있게 하여 Java 힙을 구성하는 메모리에 대한 액세스를 최적화합니다.

      기본값:off
      권장:on
      사용법:-XX:+ForceMmapReserved는 "지연 스왑"을 사용 안합니다.
    • -Xmn

      이 설정은 젋음 세대가 힙에서 소비하도록 허용되는 공간을 제어합니다. 이 매개변수를 적절하게 조정하면 가비지 콜렉션의 오버헤드를 줄여서 서버 응답 시간 및 처리량을 개선할 수 있습니다. 이 옵션에 대한 기본 설정은 일반적으로 너무 낮아서 사소한 가비지 콜렉션의 수를 높게 만듭니다.

      기본값:기본값 없음
      권장:대략 총 힙 크기의 3/4
      사용법:-Xmn768m은 크기를 768MB로 설정합니다.
    • 가상 페이지 크기

      JVM(Java Virtual Machine) 명령어 및 데이터 페이지 크기를 64MB로 설정하면 성능이 향상될 수 있습니다.

      기본값:4MB
      권장:64MB
      사용법:다음 명령을 사용하십시오. 명령 출력이 프로세스 실행 파일의 현재 운영 체제 특성을 제공합니다. <PRE>chatr +pi64M +pd64M /opt/WebSphere/
      AppServer/java/bin/PA_RISC2.0/
      native_threads/java </PRE>
    • -Xnoclassgc

      기본적으로 JVM은 클래스의 활동하는 인스턴스가 없을 때 메모리에서 해당 클래스를 로드 해제하지만, 이는 성능을 저하시킬 수 있습니다. 클래스 가비지 콜렉션을 끄면 동일한 클래스를 여러 번 로드 및 로드 해제하는 오버헤드를 제거합니다.

      클래스가 더 이상 필요없는 경우 클래스가 힙에서 차지하는 공간은 일반적으로 새 오브젝트의 작성을 위해 사용됩니다. 그러나 클래스의 새 인스턴스를 작성하여 요청을 처리하는 응용프로그램이 있고 해당 응용프로그램에 대한 요청이 임의 시간에 오는 경우, 이전 요청자가 완료될 때 다음 요청이 나타날 때만 클래스를 다시 인스턴스화하기 위해 정상 클래스 가비지 콜렉션이 클래스가 차지했던 힙 공간을 사용 가능하게 해서 이 클래스를 지우는 것이 가능합니다. 이 상황에서는 이 옵션을 사용하여 클래스의 가비지 콜렉션을 사용하지 않을 수 있습니다.

      기본값:클래스 가비지 콜렉션 사용 가능
      권장:클래스 가비지 콜렉션 사용 불가능
      사용법:Xnoclassgc가 클래스 가비지 콜렉션을 사용 불가능하게 합니다.

    HP 가상 시스템 조정에 대한 추가 정보는 Java technology software HP-UX 11i를 확인하십시오.

  •  HP-UX를 위해 HP의 JVM을 조정하십시오. 다음 옵션을 설정하여 응용프로그램 성능을 개선하십시오. <PRE>-XX:SchedulerPriorityRange=SCHED_NOAGE 
    -Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.DevPollSelectorProvider 
    -XX:-ExtraPollBeforeRead
    </PRE>

특정 상황에서 수행되는 덤프 수를 제한하십시오.

특정 오류 상황에서는 복수 Application Server 스레드가 실패하여 JVM이 해당 스레드 각각에 TDUMP를 요청합니다. 이러한 경우 많은 수의 TDUMP가 동시에 수행되어 보조 기억장치 부족과 같은 다른 문제점이 발생할 수 있습니다. JAVA_DUMP_OPTS 환경 변수를 사용하여 특정 상황에서 JVM이 생성할 덤프 수를 표시할 수 있습니다. 그러나 Application Server에서 실행 중인 응용프로그램의 com.ibm.jvm.Dump.SystemDump() 호출로 인해 생성되는 TDUMPS 수에는 영향을 주지 않습니다.

예를 들어, JAVA_DUMP_OPTS 변수를 다음 옵션과 함께 지정하는 경우 JVM의 역할은 다음과 같습니다.

  • TDUMP 토큰 수를 1로 제한합니다.
  • JAVADUMP 토큰 수를 최대값 3으로 제한합니다.
  • INTERRUPT가 발생하는 경우 문서를 캡처하지 않습니다.




출처: http://blog.naver.com/ewideplus/10085376365





주제

  메모리 관리에 관한 모든 것을 알아서 해준다는 JVM의 실체를 파악해보자.

 

Garbage Collection의 이해

 

  • Minor GC: Copy & Scavenge 알고리즘을 이용한 GC

    • Young GC: Eden영역과 S0, S1에 대해서 동작한다.

      • Eden과 S0에서 Reference가 끊어진 객체는 제거하고, 남은 객체는 S1영역으로 이동시킨다.
      • Eden과 S1에서 Reference가 끊어진 객체는 제거하고, 남은 객체는 S0영역으로 이동시킨다.
      • 위 두 동작이 반복적으로 일어난다.
    • Old GC: S0와 S1에 대해서 tenured 영역으로 동작한다.

      • 오랜 시간 라이프타임이 이어지는 객체를 Old영역으로 옮긴다. 더 정확하게는 S0와 S1 영역을 지정된 Threshold(Default 32) 값만큼 반복해서 Copy가 일어나면 Old 영역으로 이동할 대상이 되어 옮겨진다.
      •  Old 영역은 tenured 영역으로도 불리며, 이 영역에서 메모리의 일정 비율 이상 증가하면 Full GC(Major GC)가 일어나게 된다.
  • Major GC: Mark & Compact(Sweep) 알고리즘을 이용한 GC

    • 전체 객체를 대상으로 Reference를 확인하고 Marking 작업을 수행한 후 Mark된 대상 객체를 삭제하며, 삭제된 빈공간으로 객체들을 재정렬하여 조각화된 영역을 조정한다.
    • Major GC는 Permanent 영역에 대해서도 실행된다. 만약 ClassLoader에 의해 로드된 Class가 Permanent 영역의 일정 비율 이상 증가하면 Major GC가 일어나게 된다.

 

JVM 옵션

 

 

  • -Server

    • Full GC 동작이 Mark & Sweep으로 Minor GC의 동작이 Scavange 알고리즘으로 수행됨을 알 수 있다.
    • 처음 JVM 기동 시에 최적화 Compilation을  수행하므로 Client옵션에 비해 초기 기동 시간이 길다.
    • 컴파일 타임의 최적화는 주로 상수화 가능한 메소드의 inline 처리가 기본적이며, Runtime시에 충돌이 일어나는 경우 Deoptimization이 일어난다.
    • 서버 어플리케이션은 잦은 Request로 인해 Eden 영역으로 객체가 자주 생성될 것이라고 가정하는 형태로 Heap의 비율을 결정한다.
    • Minor GC의 실행 그래프를 관찰하면 일반적으로 완만한 상승과 하강의 반복 파형을 그리는 경우가 많으며, Old영역으로 비율이상의 객체가 적재되면 Full GC가 일어난다.
    • 결론: Server모드에서는 비록 Heap 메모리를 크게 잡더라도 Pooling하는 객체의 양이 지속적으로 많아지는 경우 또는 대량의 객체를 생성 후 해제하지 않는 경우에는 Full GC가 자주 발생하므로 New Generation 영역의 사이즈를 줄이는 것이 좀더 효율적일 것 이다.
  • -Client

    • Full GC 동작이 Mark & Sweep & Compact로 Minor GC의 동작이 Copy 알고리즘으로 수행됨을 알 수 있다.
    • Old Generation의 사용 빈도가 높을 것으로 예상하고, New Generation영역의 크기를 작게 하고, Threshold값을 runtime에 떨어뜨려서 Old영역으로 객체를 옮기는 작업을 수행한다.
    • Minor GC의 실행 그래프를 관찰하면 대체로 톱니 모양의 파형이 형성되는데 형성되는 간격이 짧을 수록 GC가 자주 일어난다는 의미 이므로 new generation 영역의 사이즈 조정이 필요하다.
    • 결론: client측의 어플리케이션이라 하더라도 새로운 객체를 자주 생성해야 하는 경우에 이 옵션은 비효율적임을 알 수 있다.
  • -hotspot

    • -Client와 동의어로 표기되어 있으며, Default VM 기동 옵션으로 지정되어 있으므로 의미가 없다.

 

Non-Standard Options

  • -Xms<size>

    • Heap size의 최소값을 지정한다.
    • JVM이 기동되는 환경에 따라 조정된다.
    • 기동되는 시점에 메모리를 지정된 크기 만큼 할당한다.
  • -Xmx<size>

    • Heap size의 최대값을 지정한다.
    • 최대값에 할당되는 크기는 Java Heap size만이며, Heap을 제외한 나머지 영역은 별도의 크기를 가진다.
    • 1GB 이상 크게 잡기 위해서는 별도의 Option을 지정해야 한다고 한다. (여기에 대한 자세한 내용은 찾지 못했음)
  • -XX:MaxPermSize=<size>

    • Permanent 영역의 최대 크기를 지정할 수 있으며, 이 영역을 크게 잡으면 상대적으로 객체의 저장 영역이 줄어들어 성능의 저하 및 OutOfMemory Exception을 발생시킬 수 있고, 반대로 너무 작아도 OutOfMemory Exception이 발생한다.
    •  Perm 영역에는 Class의 Method 바이트코드, Class들의 Signature, 상수값, 객체배열과 배열의 요소들의 타입정보 그리고 참조하고 있는 메소드 정보, JVM이 생성하는 internal object(java.lang.object, java.lang.exception등의 instance), 컴파일러 최적화를 위한 정보 (CPU, Memory등의 JVM 기동환경 정보 등)
  •  -XX:NewSize=<size>

    • New generation영역의 최대 크기를 지정할 수 있으며, 이 영역을 크게 잡으면 상대적으로 Perm영역이 줄어 들게 된다.

 

 

 

상황별, GC 옵션별 예제

Out of Memory Perm Area over flow

-XX:-UseSerialGC
-Xms32m
-Xmx32m
-XX:MaxPermSize=3m
-XX:NewSize=2m


Frequently Full GC
-Xms5m
-Xmx5m
-XX:MaxPermSize=10m
-XX:NewSize=1m

 

ParallelGC server

-server
-XX:-UseParallelGC
-Xms1024m
-Xmx1024m
-XX:MaxPermSize=200m
-XX:NewSize=10m

 

Parallel Old GC server

-server
-XX:-UseParallelOldGC
-Xms1024m
-Xmx1024m
-XX:MaxPermSize=200m
-XX:NewSize=10m

 

Serial GC server

-server
-XX:-UseSerialGC
-Xms1024m
-Xmx1024m
-XX:MaxPermSize=200m
-XX:NewSize=10m

 

 G1 server

-server
-Xms1024m
-Xmx1024m
-XX:MaxPermSize=200m
-XX:NewSize=10m
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

 

마침

 JVM과 GC에 대해서 간단하게 살펴 보았습니다. 우선 이 글의 주제가 Tuning이 아님을 알아 주셨으면 합니다. Java코드가 실제 기동시에 객체로서 메모리에 적재되고, 관리되는 방식과 발생할 수 있는 위험에 대해서 미연에 방지하기 위한 기본 개념을 가지자는 것이 이 글의 주제입니다. 현업에서라면 오히려 메모리의 문제보다는 File Descriptor나 Database Connection 또는 Server Connection등의 외부 자원들의 관리 이슈가 더 클지도 모릅니다. 그리고 주로 문제를 일으키는 부분은 JVM이기 보다 코드에서의 문제가 더 많기도 합니다.

 

  로버트 C 마틴은 클린코드에서 최소 놀람의 원칙(The Principle of Least Surprise) 이라는 이야기를 했는데요. client모드와 server모드에서 각각 이럴 것이다 라고 가정한 부분을 뒤집어 버린다면 자바가 자랑스럽게 문서에 써넣은  ergonomics라는 단어는 별 의미가 없을 것 이고, 이런 정도의 커스터마이징이라면 그 수준에 맞는 환경으로 운영하는 것이 여러모로 알맞은 선택이 될 것 같습니다.

 

 

 

References



출처 -  http://guysheep.tistory.com/81








출처 -  Http://Wiki.Ex-Em.Com/Index.Php/JVM_Options 

JVM Options

목차

 [숨기기]

[편집]개요

[편집]왜 JVM Option을 알아야 하는가

Java 언어는 하드웨어/OS에 독립적이다. 즉, Java로 작성된 Application은 아무런 수정없이 JVM이 구동가능한 어떤 OS에서도 동작한다. 하지만 이것은 "동작"의 독립성일 뿐 "성능"의 독립성이 아니다.

특정 OS의 특정 JDK 버전에서 아무런 성능 문제없이 구동되었던 Application이 다른 OS나 다른 버전의 JDK에서는 심각한 성능 문제를 겪는 사례가 종종 있다. Java 언어와 Bytecode는 독립성을 가지고 있지만, Bytecode를 실행하는 JVM은 그렇지 않기 때문이다. 이러한 종류의 성능 문제를 해결하려면 JVM이 제공하는 Options들에는 어떤 것이 있고 Option의 적용에 따라 어떤 차이가 나타나는지 정확하게 이해해야 한다.


[편집]Standard vs. Non-Standard Option

Standard Option은 JVM 표준이다. 즉 Sun HotSpot JVM, IBM JVM, BEA JRockit JVM, HP HotSpot JVM 등 모든 JVM이 동일한 Option을 제공한다.

반면 Non-Standard Option은 JVM의 표준이 아니다. 따라서 JVM의 버전과 OS 종류에 따라 존재여부가 결정된다. 언제든지 추가되거나 없어지기도 한다. 이런 면에서 Non-Standard Option들은 골칫거리처럼 여겨질 수 있다. 하지만, 다음과 같은 측면에서 반드시 필요한 존재이기도 하다.

  • JVM 구동에 필요한 설정값(Configuration Value)를 지정할 수 있다.
  • 성능 개선에 필요한 Parameter 값을 지정할 수 있다.
  • Bug나 오동작에 의한 Workaround로 활용할 수 있다.

Non-Standard Option을 모르더라도 Java Application을 작성하고 구동하는데 전혀가 문제가 없을 수도 있다. 하지만 조그만한 오동작이나 성능 저하만 발생해도 Non-Standard Option 도움 없이는 해결할 수 없는 경우가 많다. 따라서 시스템 관리자나 개발자들은 중요한 Non-Standard Option들에 대해 어느 정도 이해하고 있어야 한다.

Non-Standard Option은 다음 두 개의 범주로 구분된다.

  • -X Option: 일반적인 Non-Standard Option이다. Macro한 측면에서의 JVM 제어 기능을 제공한다. -X Option은 JVM마다 다르지만 일부 Option들은 마치 Standard Option처럼 사용된다.
  • -XX Option: -X Option보다 보다 세밀한 제어 기능을 제공한다. Micro한 측면에서의 JVM 기능을 제공한다. 세밀한 성능 튜닝이나 버그에 대한 Workaround를 위해서 주로 활용된다. -XX Option은 JVM 종류에 따라 완전히 다르다.

[편집]Option 지정하기

JVM Option을 지정하는 방법의 예는 다음과 같다.

  1. 단일값: -client Option과 같이 옵션을 지정하면 그 자체로 의미를 지닌다.
  2. 크기(Size): -Xmx1024m과 같이 크기(K,M,G)를 지정한다.
  3. 숫자(Int): -XX:SurviorRatio=10과 같이 숫자값을 지정한다.
  4. 문자열(String): -agentlib:hprof=cpu=samples과 같이 문자열을 지정한다.
  5. Boolean: -XX:+PrintGCDetails 혹은 -XX:-PrintGCDetails와 같이 +/-를 이용해서 활성화/비활성 여부를 지정한다.

[편집]Sun HotSpot JVM (1.5 기준)

[편집]Standard Options

OptionDescription
-clientClient HotSpot JVM을 사용한다. Client HotSpot JVM은 Desktop용 Application을 구동하는데 유리하다. 성능 최적화(Optimization) 과정을 간략화함으로써 Application의 시작 시간을 최소화한다.
-serverServer HotSpot JVM을 사용한다. Server HotSpot JVM은 Server용 Application을 구동하는데 유리하다. 성능 최적화(Optimization)에 필요한 모든 과정을 최대한으로 수행한다. Application의 시작 시간은 느리지만, 일정 시간이 흐르면 Client HotSpot JVM에 비해 훨씬 뛰어난 성능을 보장한다.

(참고)Jdk 1.5부터는 Server-Class 머신인 경우에는 -server 옵션이 기본 적용된다. Server-Class 머신이란 2장 이상의 CPU와 2G 이상의 메모리를 갖춘 머신을 의미한다.

-d3232bit JVM을 사용한다. 32bit JVM은 메모리를 최대 2G까지만 사용할 수 있다. 반면 일반적인 수행 성능 64bit JVM에 비해 뛰어난 경우가 많다. 따라서 큰 크기의 Java Heap을 사용하지 않는 경우에는 비록 64bit 머신이라고 하더라도 32bit JVM을 사용하는 것이 권장된다.
-d6464bit JVM을 사용한다. 64bit JVM에서 사용가능한 메모리의 크기에는 사실상 제한이 없다. 대형 Application들의 경우 수G ~ 수십G의 Java Heap을 사용하는 경우가 많다.
-agentlib:<libname>[=<options>]Native Agent Library를 로딩한다. Native Agent Library란 JVMPI/JVMTI를 구현한 Library를 의미하며 C/C++로 구현된다. JVM은 Unix/Linux에서는 lib<libname>.so 파일이, Windows에서는 <libname>.dll 파일을 탐색한다. 해당 파일은 현재 Directory나 PATH 변수에 등록된 Directory에 존재해야 한다.

(참조) JDK 1.4까지는 HProf를 실행시키기 위해 -Xrunhprof:option=value 옵션을 사용한다. JDK 1.5부터는 -Xagentlib:hprof=option=value 옵션이 권장된다. -Xrunhprof 옵션은 차후 없어질 수 있다.

-agentpath:<pathname>[=<options>]-agentlib 옵션과 동일한 기능이다. Library 이름 대신 Full Path 명을 준다.
-javaagent:<jarpath>[=<options>]Java Agent Library를 로딩한다. Java Agent는 Native Agent가 C/C++로 구현되는 것과 달리 Java로 구현된다. java.lang.instrument Package를 통해 Java Agent를 구현하는 필요한 Interface가 제공된다. Java Agent는 BCI를 통해 Runtime에 Class들의 Bytecode를 변경하는 방법을 통해 작업을 수행한다.

[편집]Non-Standard Options (-X)

OptionDescription
-Xbootclasspath[/a|/p]:<path>Boot class path를 제어한다. /a 옵션은 Boot class path의 제일 뒤에 Append, /p 옵션은 제일 앞에 Prepend한다. 일반적인 환경에서는 Boot class path를 제어할 필요가 없다. Java Core Library(rt.jar 등)등에 대해 Reverse Engineering을 수행하고 행동 방식을 변경하고자 할 경우에 주로 활용된다.
-xcheck:jni
-XintIntepreter 모드로만 ByteCode를 실행한다. Interpreter 모드로 실행될 경우에는 JIT Compile 기능이 동작하지 않는다. 이 옵션을 활성화하면 실행 속도이 다소 저하될 수 있다. 따라서 HotSpot Compiler의 버그로 문제가 생길 때만 사용이 권장된다.
-XnoclassgcClass Garbage Collection을 수행하지 않는다.
-Xloggc:<file>GC Log를 기록할 파일명을 지정한다. 파일명을 지정하지 않으면 Standard Out이나 Standard Error 콘솔에 출력된다. 주로 -XX:+PrintGCTimeStamps, -XX:+PrintGCDetails 옵션과 같이 사용된다.
-XmixedMixed 모드로 ByteCode를 실행한다. HotSpot JVM의 Default 동작 방식이며, -Xint 옵션과 상호 배타적인 옵션이다.
-Xmn<size>Young Generation이 거주하는 New Space의 크기를 지정한다. 대개의 경우 이 옵션보다는 -XX:NewRatio 옵션이나 -XX:NewSize 옵션을 많이 사용한다.
-Xms<size>Java Heap의 최초 크기(Start Size)를 지정한다. Java Heap은 -Xms 옵션으로 지정한 크기로 시작하며 최대 -Xmx 옵션으로 지정한 크기만큼 커진다. Sun HotSpt JVM 계열에서는 최초 크기와 최대 크기를 동일하게 부여할 것을 권장한다. 크기의 동적인 변경에 의한 오버 헤드를 최소화하기 위해서이다.
-Xmx<size>Java Heap의 최대 크기(Maximum Size)를 지정한다. Java Heap은 -Xms 옵션으로 지정한 크기로 시작하며 최대 -Xmx 옵션으로 지정한 크기만큼 커진다. Sun HotSpt JVM 계열에서는 최초 크기와 최대 크기를 동일하게 부여할 것을 권장한다. 크기의 동적인 변경에 의한 오버 헤드를 최소화하기 위해서이다.
-Xrunhprof[:help][:option=value,...]HProf(Heap and CPU Profiling Agent)를 실행한다. HProf는 JVMPI/JVMTI를 이용해 구현된 Sample Profiler이다. 비록 Sample에 불과하지만, 많은 경우 HProf만으로도 상당히 유용한 정보들을 얻을 수 있다.
-XrsOS Signal사용을 최소화한다. 가령 이 옵션을 켜면 kill -3 [pid] 명령을 수행해도 Thread dump가 발생하지 않는다.
-Xss<size>개별 Thread의 Stack Size를 지정한다. 예를 들어 Thread Stack Size가 1M이고, Thread가 최대 100개 활성화된다면, 최대 100M의 메모리를 사용하게 된다. 대부분의 경우 기본값(Default)을 그대로 사용하는 것이 바람직하다. 많은 수의 Thread를 사용하는 Application의 경우 Thread Stack에 의한 메모리 요구량이 높아지며 이로 인해 Out Of Memory Error가 발생할 수 있다. 이런 경우에는 -Xss 옵션을 이용해 Thread Stack Size를 줄여주어야 한다.

[편집]Non-Standard Options (-XX)

-XX 옵션 중 Boolean 유형은 접두어로 +를 붙이면 활성화(Enable), -를 붙이면 비활성화(Disable)를 의미한다.

OptionDefaultDescription
-XX:+AggressiveHeapFalse말 그대로 Heap을 Aggressive(공격적)하게 사용하는 옵션이다. 이 옵션이 활성화되면 JVM은 현재 Application을 Memory-Intensive한 것으로 간주하고 Heap 공간을 최대한 사용하게끔 관련된 다른 옵션 값들을 결정한다. 가령UseParallelGC 옵션을 활성화시키고, Java Heap의 크기를 Physical Memory의 최대치에 가깝게 설정한다. 
이 옵션은 비록 사용하기는 간편하지만, 일반적으로 잘 사용되지는 않는다. 대부분의 경우, 개별적인 옵션들을 이용해 좀 더 세밀한 튜닝을 시도한다.
-XX:+CMSClassUnloadingEnabledFalseCMS Collector는 Permanent Generation에 대해 GC 작업을 수행하지 않으며, Class 메타데이터에 대한 Unloading 작업 또한 수행하지 않는다. 따라서 Application의 특성상 많은 수의 Class를 동적으로 생성하고 Loading하는 경우에는 Permanent Generation에서 Out Of Memory Error가 발생할 수 있다. 이런 경우에는 이 옵션과 함께 CMSPermGenSweepingEnabled 옵션을 사용해서 Permanent Generation에 대한 GC 작업과 Class Unloading 작업을 활성화한다. JDK 1.5까지는 이 두 옵션을 모두 활성화해야 Class Unloading이 이루어진다. JDK 1.6부터는 CMSPermGenSweepingEnabled 옵션을 활성화하지 않아도 이 옵션이 작동한다.
-XX:CMSFullGCsBeforeCompaction=<value>-1CMS Collector에서 Compaction(압축)을 수행하기 전에 Full GC를 수행할 회수를 지정한다. 일반적인 Full GC는 Compaction 작업을 수반한다. 반면에 CMS Collector의 Full GC는 Compaction을 수행하지 않는다. 이로 인해 Heap의 Fragmentation이 발생할 수 있지만, Full GC에 의한 Pause Time을 최소화할 수 있다는 장점이 있다.

이 옵션은 Compaction의 발생 시점을 제어하는 역할을 한다. 예를 들어 이 값이 "1"인 경우, Concurrent Full GC가 아직 종료되지 않은 시점에 새로운 Concurrent Full GC 작업이 시작되면(1), Compaction이 수반된다. 만일 이 값이 "0"인 경우에는 Concurrent Full GC는 "항상" Compaction을 수반한다. 따라서 CMS Collector를 사용하는 환경에서 Heap Fragmentation에 의한 문제가 발생하는 경우에는 "0"의 값을 부여하는 것이 Workaround가 될 수 있다.

-XX:+CMSIncrementalModeFalseFull GC 작업을 Incremental하게 진행한다. 일반적으로 CMS Collector는 Old Generation가 어느 정도 이상 점유되면 Concurrent Full GC 작업을 시작한다. 반면 이 옵션이 활성화되면 Old Generation의 사용률과 무관하게 백그라운드에서 점진적으로(Incremental) Old Generation에 대한 GC 작업을 수행한다. 이 옵션을 사용하면CMSInitiatingOccupancyFraction 옵션은 무시된다. 

이 옵션을 활성화하면 Throughput은 다소 줄어들고, Response Time은 좀 개선되는 경향이 있다. 따라서 GC 작업 Pause를 더 줄이고 싶을 경우에 사용할 수 있다.

-XX:CMSInitiatingOccupancyFraction=<value>-1CMS Collection이 시작되는 임계값을 결정한다. 만일 이 값이 "50"이면 Old Generation이 50% 이상 사용되면 Concurre Full GC가 시작된다. 이 값의 기본값은 "-1"이다. 이 경우에는 CMSTriggerRatio 옵션과MinHeapFreeRatio 옵션이 임계치로 사용된다. 임계치의 계산 공식은 다음과 같다.

Start Ratio = 100-MinHeapFreeRatio(=40) + MinHeapFreeRatio(=40) * (CMSTriggerRatio(=80)/100) = 92 
즉, CMSInitiatingOccupancyFraction 옵션이 지정되지 않으면 Old Generation이 92% 정도 사용될 때Concurrent Full GC가 시작된다.
이 옵션을 지정하면 50%에서 시작하여, 옵션으로 지정된 값까지 점진적으로 임계값을 조정한다. 만일 임계값을 고정하고자 할 경우에는 UseCMSInitiatingOccupancyOnly 옵션을 활성화해야 한다.
이 옵션의 값이 작으면 CMS Collection이 그만큼 빨리 동작하기 때문에 Promotion Failure에 의한 Stop The World GC 작업이 발생할 확률이 그만큼 줄어든다.

-XX:+CMSPermGenSweepingEnabledFalseCMS Collector는 기본적으로 Permanent Generation에 대해 Collection을 수행하지 않는다. 따라서 많은 수의 Class를 Loading하는 경우 Out Of Memory Error가 발생할 수 있다. 이 옵션을 활성화하면 Permanent Generation에 대한 Collection을 수행한다. JDK 1.5까지는 이 옵션과 함께 CMSClassUnloadingEnabled 옵션을 활성화해야 동작한다.
-XX:CompilerCommandFile=<file>.hotspot_compilerCompiler Command File의 위치를 지정한다.
-XX:+DisableExplicitGCFalseSystem.gc 호출에 의한 Explicit GC를 비활성화한다. RMI에 의한 Explicit GC나 Application에서의 Explicit GC를 원천적으로 방지하고자 할 경우에 사용된다.
-XX:GCHeapFreeLimit=<Percentage>5Parallel Collector를 사용할 때 GC도중 Out Of Memory Error의 발생을 방지하는데 도움을 준다. GC로 확보해야할 Free Space의 하한선을 결정한다. 이 값은 Max Heap 크기에 대한 Free 공간 크기의 비율이며 기본값은 "5"이다. 즉 Parallel Collection 후 확보해야할 Free 공간 크기가 적어도 Max Heap 크기의 5% 이상이 되도록 보장하는 것이다.
-XX:GCTimeLimit=<Percentage>90Parallel Collector를 사용할 때 GC도중 Out Of Memory Error의 발생을 방지하는데 도움을 준다. 전체 JVM 수행시간 대비 Parallel Collection 수행 시간의 상한선를 결정한다. 기본값은 "90"이다. 즉 Parallel Collection이 전체 수행 시간의 90%까지 사용할 수 있게 된다.
-XX:+HeapDumpOnOutOfMemoryErrorFalseOut Of Memory Error가 발생하면 Heap Dump를 File에 기록한다. JDK 1.6 부터 지원되는 옵션이다.
-XX:MaxGCMinorPauseMillis=<Value>NoneMinor GC에 의한 Pause Time을 <value>ms 이하가 되게끔 Heap 크기와 기타 옵션들을 자동으로 조정하는 기능을 한다. 이 값은 목표값(Target)이지 고정값이 아니다. Minor GC에 의한 Pause Time이 길 경우에 Workaround로 사용할 수 있다.
-XX:MaxGCPauseMillis=<Value>NoneGC에 의한 Pause Time을 <value>ms 이하가 되게끔 Heap 크기와 기타 옵션들을 자동으로 조정하는 기능을 한다. MaxGCMinorPauseMillis 옵션과 마찬가지로 목표값으로서의 역할을 한다. GC에 의한 Pause Time이 길 경우에 Workaround로 사용할 수 있다.
-XX:MaxHeapFreeRatio=<Value>70Heap Shrinkage를 수행하는 임계치를 지정한다. 예를 들어 이 값이 70이면 Heap의 Free 공간이 70% 이상이 되면 Heap 크기가 축소된다. MinHeapFreeRatio 옵션과 함께 Heap의 크기 조정을 담당한다.
-XX:MaxNewSize=<Value>NoneYoung Generation의 최대 크기를 지정한다. Young Generation의 시작 크기는 NewSize 옵션에 의해 지정된다.
-XX:MaxPermSize=<Value>NonePermanent Generation의 최대 크기를 지정한다. Permanent Generation의 시작 크기는 PermSize 옵션에 의해 지정된다. 많은 수의 Class를 Loading하는 Application은 PermSize와 MaxPermSize 옵션을 이용해 Permanent Generation의 크기를 크게 해주는 것이 좋다. Permanent Generation의 크기가 작을 경우에는 Out Of Memory Error가 발생할 수 있다.
-XX:MinHeapFreeRatio=<Value>40Heap Expansion을 수행하는 임계치를 지정한다. 예를 들어 이 값이 40이면 Heap의 Free 공간이 40% 미만이 되면 Heap 크기가 확대된다. MaxHeapFreeRatio 옵션과 함께 Heap의 크기 조정을 담당한다.
-XX:NewRatio=<Value>OS/JDK Version마다 다름Young Generation과 Old Generation의 비율을 결정한다. 예를 들어 이값이 2이면 Young:Old = 1:2 가 되고,Young Generation의 크기는 전체 Java Heap의 1/3이 된다.
-XX:NewSize=<Value>OS/JDK Version마다 다름Young Generation의 시작 크기를 지정한다. Young Generation의 크기는 NewSize 옵션(시작 크기)과MaxNewSize 옵션(최대 크기)에 의해 결정된다.
-XX:OnError=<Command>NoneFatal Error가 발생할 경우(예: Native Heap에서의 Out Of Memory Error), <Command>로 지정된 OS 명령문을 수행한다. 비정상적인 JVM 장애 현상을 좀 더 자세하게 분석하고자 할 경우에 주로 사용된다.
-XX:OnError="pmap %p" 
 --> JVM에서 Fatal Error가 발생하면 Process ID에 대해 pmap 명령을 수행한다.
-XX:OnOutOfMemoryError=<Command>NoneOut Of Memory Error가 발생할 경우, <Command>로 지정된 OS 명령문을 수행한다. JDK 1.6에 추가된 옵션으로, Out Of Memory Error가 Java에서 얼마나 보편적으로 발생하는지를 알 수 있다. 
-XX:OnOutOfMemoryError="pmap %p" 
 --> JVM에서 Fatal Error가 발생하면 Process ID에 대해 pmap 명령을 수행한다.
-XX:ParallelGCThreads=<value>CPU 개수Parallel Collector를 사용할 경우, GC작업을 수행할 Thread의 개수를 지정한다. 기본값은 CPU 개수이다. 즉, Parallel GC 작업을 수행하기 위해 시스템 전체의 CPU를 최대한 활용한다. 하나의 Machine에 여러 개의 JVM을 구동하는 환경이나, 하나의 Machine을 여러 종류의 Application이 공유해서 사용하는 환경에서는 이 옵션의 값을 낮게 설정해서 GC Thread의 개수를 줄임으로써 성능 개선을 꾀할 수 있다. Context Switching에 의한 성능 저하를 막을 수 있기 때문이다.
-XX:PermSize=<size>Permanent Generation의 최초 크기를 지정한다. Permanent Generation의 최대 크기는 MaxPermSize 옵션에 의해 지정된다. 많은 수의 Class를 로딩하는 Application은 큰 크기의 Permanent Generation을 필요로 한며,Permanent Generation의 크기가 작아서 Class를 로딩하는 못하면 Out Of Memory Error가 발생한다.
-XX:PretenureSizeThreshold=<value>0일반적으로 Object는 Young Generation에 최초 저장된 후 시간이 흐름에 따라 Tenured Generation으로 Promotion된다. 하지만, Object의 크기가 Young Generation보다 큰 경우 JVM은 Old Generation에 Object를 직접 저장하기도 한다. PretenuredSizeThreshold 옵션을 이용하면 Young Generation을 거치지 않고 직접 Old Generation에 저장하게끔 할 수 있다. 가령 이 옵션의 값이 1048576(1M)이면, 1M 크기 이상의 오브젝트는 Old Generation에 바로 저장된다. 

큰 크기의 오브젝트를 Old Generation에 직접 저장함으로써 불필요한 Minor GC를 줄이고자 하는 목적으로 사용된다.

-XX:+PrintGCApplicationStoppedTimeFalseApplication에서 Stop이 발생한 경우 소요된 시간 정보를 기록한다. 이 시간은 GC 작업 자체에 의한 Stop 뿐만 아니라 JVM의 내부적인 이유로 Application Thread들을 Stop 시킨 경우를 포함한다.
-XX:+PrintGCDetailsFalseGC 발생시 Heap 영역에 대한 비교적 상세한 정보를 추가적으로 기록한다. 추가적인 정보는 {GC 전 후의 Young/Old Generation의 크기, GC 전 후의 Permanent Generation의 크기, GC 작업에 소요된 시간} 등이다.Minor GC가 발생한 경우 PrintGCDetails 옵션의 적용 예는 아래와 같다.
[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]

위의 로그가 의미하는 바는 다음과 같다.

  • GC 전의 Young Generation Usage = 64M, Young Generation Size = 64M
  • GC 전의 Total Heap Usage = 196M, Total Heap Size = 260M
  • GC 후의 Young Generation Usage = 9.5M
  • GC 후의 Total Heap Usage = 133M
  • Minor GC 소요 시간 = 0.0457646 초

Major GC가 발생한 경우 PrintGCDetails 옵션의 적용 예는 아래와 같다.

111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]
111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]

위의 로그는 Minor GC 정보 외에 다음과 같은 Major GC 정보를 제공한다.

  • GC 전의 Tenured Generation Usage = 18M, Tenured Generation Size = 24M
  • GC 후의 Tenured Generation Usage = 2.3M
  • Major GC 소요시간 = 0.12초

(참고) PrintGCDetails + PrintGCTimeStamps 옵션의 조합이 가장 보편적으로 사용된다.

-XX:+PrintGCTimeStampsFalseGC가 발생한 시간을 JVM의 최초 구동 시간 기준으로 기록한다.

(참고) PrintGCDetails + PrintGCTimeStamps 옵션의 조합이 가장 보편적으로 사용된다.

-XX:+PrintHeapAtGCFasleGC 발생 전후의 Heap에 대한 정보를 상세하게 기록한다. PrintHeapAtGC 옵션과 PrintGCDetails 옵션을 같이 사용하면 GC에 의한 Heap 변화 양상을 매우 정확하게 파악할 수 있다. 아래에 PrintHeapAtGC 옵션의 적용 예가 있다.
0.548403: [GC {Heap before GC invocations=1:
Heap
par new generation total 18432K, used 12826K [0xf2800000, 0xf4000000, 0xf4000000]
eden space 12288K, 99% used<1> [0xf2800000, 0xf33ff840, 0xf3400000]
from space 6144K, 8% used<2> [0xf3a00000, 0xf3a87360, 0xf4000000]
to space 6144K, 0% used<3> [0xf3400000, 0xf3400000, 0xf3a00000]
concurrent mark-sweep generation total 40960K, used 195K<4>[0xf4000000, 0xf6800000, 0xf6800000]
CompactibleFreeListSpace space 40960K, 0% used [0xf4000000, 0xf6800000]
concurrent-mark-sweep perm gen total 4096K, used 1158K<5> [0xf6800000, 0xf6c00000, 0xfa800000]
CompactibleFreeListSpace space 4096K, 28% used [0xf6800000, 0xf6c00000]
0.549364: [ParNew: 12826K<6>->1086K<7>(18432K<8>), 0.02798039 secs] 13022K->1282K(59392K)
Heap after GC invocations=2:
Heap
par new generation total 18432K, used 1086K [0xf2800000, 0xf4000000, 0xf4000000]
eden space 12288K, 0% used<10> [0xf2800000, 0xf2800000, 0xf3400000]
from space 6144K, 17% used<11> [0xf3400000, 0xf350fbc0, 0xf3a00000]
to space 6144K, 0% used<12> [0xf3a00000, 0xf3a00000, 0xf4000000]
concurrent mark-sweep generation total 40960K, used 195K<13> [0xf4000000, 0xf6800000, 0xf6800000]
CompactibleFreeListSpace space 40960K, 0% used [0xf4000000, 0xf6800000]
concurrent-mark-sweep perm gen total 4096K, used 1158K<14> [0xf6800000, 0xf6c00000, 0xfa800000]
CompactibleFreeListSpace space 4096K, 28% used [0xf6800000, 0xf6c00000]
} , 0.0297669 secs]
-XX:SoftRefLRUPolicyMSPerMB=<value>1000(ms)Soft Reference가 Java Heap에서 밀려나는 주기를 설정한다. 기본값이 1000ms(1초)이다. JDK 1.3.1까지는Soft Reference는 GC 작업 발생시 항상 메모리에서 해제되었다. 하지만 이후 버전에서는 Free Memory에 비례해 일정 시간 정도 메모리에 보관하게끔 변경되었다. 가령 이 값이 1000(1초)이면, Heap의 Free Memory 1M마다 바로 직전에 참조된 시간에서 1초가 지나지 않았다면 메모리에서 해제하지 않는다.

이 값을 크게 부여하면 Soft Reference가 그만큼 오래 메모리에 머물고 사용 효율이 높아진다. 반면 메모리 점유율이 높아진다. 따라서 Applicaiton에서 Soft Reference를 많이 사용하고, Free Memory가 많지 않은 상황에서는 이 값을 낮출 필요가 있다. 반면 Soft Reference에 기반하여 Cache를 구현하고, Free Memory에 여유가 있는 상황에서는 이 값을 높임으로써 성능 향상을 꾀할 수 있다.

-XX:SurvivorRatio=<value>5~6(OS/Version마다 다름)Survivor Space와 Eden Space의 비율을 지정한다. 만일 이 값이 6이면, To Survivor Ratio:From Survivor Ratio:Eden Space = 1:1:6이 된다. 즉, 하나의 Survivor Space의 크기가 Young Generation의 1/8이 된다.Survivor Space의 크기가 크면 Tenured Generation으로 옮겨가지 전의 중간 버퍼 영역이 커지는 셈이다. 따라서Full GC의 빈도를 줄이는 역할을 할 수 있다. 반면 Eden Space의 크기가 줄어들므로 Minor GC가 자주 발생하게 된다.
-XX:+TraceClassLoadingFalseClass Loading을 추적하는 메시지를 뿌릴지의 여부를 지정한다. TraceClassUnloading 옵션과 함께 ClassLoader 문제를 추적하고자 할 때 사용된다.
-XX:+TraceClassUnloadingFalseClass Unloading을 추적하는 메시지를 뿌릴지의 여부를 지정한다. TraceClassLoading 옵션과 함께 ClassLoader 문제를 추적하고자 할 때 사용된다. 이 옵션은 JDK 1.6에서 추가되었다.
-XX:+UseAdaptiveSizePolciyTrueParallel Collector를 사용할 경우 Young Generation의 크기를 Adaptive하게 적용할 지의 여부를 지정한다.Parallel Collector의 목적은 Throughput을 최대화하는 것이며, 이 목적에 따라 Young Generation의 크기를 JVM 스스로 조정한다.

(주의) Adaptive Size를 사용하는 경우 Young Generation의 크기가 잘못 계산되어 Full GC를 과잉 유발하는 것과 같은 오동작을 하는 경우가 있다. 이럴 경우에는 이 옵션의 값을 False(-XX:-UseAdaptiveSizePolicy)로 변경해주어야 한다.

-XX:+UseCMSCompactAtFullCollectionTrueCMS Collector에 의한 Concurrent GC 수행 시 Compaction 작업을 수행할 지의 여부를 지정한다. 이 값이 True이면, Old Generation의 Fragmentation에 의해 Promotion Failure가 발생할 때 Stop The World 방식의 Full GC를 수행하며 Compaction이 이루어진다. JDK 1.4.2부터는 True가 Default 값이다. 좀 더 자세한 내용은CMSFullGCsBeforeCompaction 파라미터를 참조한다.
-XX:+UseCMSInitiatingOccupancyOnlyFalseConcurrent Full GC를 수행할 기준으로 최초에 지정된 비율을 고정적으로 사용할지의 여부를 지정한다. 최초의 비율은 CMSInitiatingOccupancyFraction 옵션에 의해 지정된다. 

CMS Collector를 사용하는 환경에서 Full GC가 자주 발생하는 경우 CMSInitiatingOccupancyFraction 옵션의 값을 낮게(50이하)로 지정하고, 이 옵션의 값을 True로 지정하는 방법을 많이 사용한다.

-XX:+UseConcMarkSweepGCFalseCMS Collector를 사용할 지의 여부를 지정한다. GC Pause에 의한 사용자 응답 시간 저하 현상을 줄이고자 할 경우에 사용이 권장된다.
-XX:+UseParallelGC환경에 따라 다름Parallel Collector를 사용할 지의 여부를 지정한다. JDK 1.4까지는 False가 기본값이다. JDK 1.5부터는 서버급 머신인 경우에는 True, 클라이언트급 머신일 경우에는 False가 기본값이다. 서버급 머신이란 CPU가 2개 이상, Physical RAM이 2G 이상인 머신을 의미한다. 큰 크기의 Young Generation이 일반적인 엔터프라이즈 환경에서는Parallel Collector를 사용함으로써 Minor GC에 의한 GC Pause를 최소화할 수 있다. Parallel Collector는 Young Generation에 대해서만 작동한다는 사실에 주의하자. Old Generation에 대해 Parallel Collection을 사용하고자 하는 경우에는 UseParallelOldGC 옵션을 사용한다.
-XX:+UseParallelOldGCFalseOld Generation에 대해 Parallel Collection을 수행할 지의 여부를 지정한다. JDK 1.6에서 추가된 옵션이다.
-XX:+UseParNewGC환경에 따라 다름CMS Collector를 사용하는 경우에 한해서, Young Generation에 대해서 Parallel Collection을 수행할 지의 여부를 지정한다. 이 옵션과 UseParallelGCUseParallelOldGC 옵션과의 차이를 명확하게 구분해야 한다.
-XX:+UseSerialGC환경에 따라 다름Serial Collector를 사용할 지의 여부를 지정한다. JDK 1.4까지는 Default 값이 True이다. JDK 1.5에서는UseParallelGC 옵션에서 설명한 것처럼 머신의 등급에 따라 Default 값이 결정된다.

[편집]IBM JVM (1.5 기준)

Sun Hotspot JVM이 반드시 Command Line에서 JVM Option을 지정해주어야 하는 반면, IBM JVM에서는 다음과 같은 세 가지 방법으로 Option을 지정할 수 있다.

  • Command Line: java -Xgcpolicy:optthruput 과 같은 형태로 지정
  • Options File: –Xoptionsfile 옵션을 이용해서 Option을 모아둔 Text File을 지정. Optionsfile은 다음과 같은 형태이다.
#My options file
-X<option1>
-X<option2>=\<value1>,\
      <value2>
-D<sysprop1>=<value1>
  • IBM_JAVA_OPTIONS 환경변수: IBM_JAVA_OPTIONS 환경변수에 값을 지정(예: IBM_JAVA_OPTIONS=-X<option1> -X<option2>=<value1>)


[편집]Standard Options

OptionDescription
-memorycheck:<optiton>JVM 내부에서 발생하는 Memory Leak을 추적하기 위한 용도로 사용된다. JVM 기술지원 엔지니어들이 사용하는 용도로 보면 정확한다. JVM 자체는 C/C++로 구현되었다. 따라서 JVM 내부에서 발생하는 Memory Leak은 Java에서 발생하는 것과는 달리 진정한 의미에서는 Memory Leak으로 이해할 수 있다. 다음과 같은 옵션들이 제공된다(IBM JVM Diagnositics Guide에서 발췌)
  • all - The default if just -memorycheck is used. Enables checking of all allocated and freed blocks on every free and allocate call. This check of the heap is the most thorough and should cause the JVM to exit on nearly all memory-related problems very soon after they are caused. This option has the greatest impact on performance.
  • quick - Enables block padding only. Used to detect basic heap corruption. Pads every allocated block with sentinel bytes, which are verified on every allocate and free. Block padding is faster than the default of checking every block, but is not as effective.
  • nofree - Keeps a list of already used blocks instead of freeing memory. This list is checked, along with currently allocated blocks, for memory corruption on every allocation and deallocation. Use this option to detect a dangling pointer (a pointer that is "dereferenced" after its target memory is freed). This option cannot be reliably used with long-running applications (such as WAS), because "freed" memory is never reused or released by the JVM.
  • failat=<number of allocations> - Causes memory allocation to fail (return NULL) after <number of allocations>. Setting <number of allocations> to 13 will cause the 14th allocation to return NULL. Deallocations are not counted. Use this option to ensure that JVM code reliably handles allocation failures. This option is useful for checking allocation site behavior rather than setting a specific allocation limit.
  • skipto=<number of allocations> - Causes the program to check only on allocations that occur after <number of allocations>. Deallocations are not counted. Used to speed up JVM startup when early allocations are not causing the memory problem. As a rough estimate, the JVM performs 250+ allocations during startup.
  • callsite=<number of allocations> - Prints callsite information every <number of allocations>. Deallocations are not counted. Callsite information is presented in a table with separate information for each callsite. Statistics include the number and size of allocation and free requests since the last report, and the number of the allocation request responsible for the largest allocation from each site. Callsites are presented as sourcefile:linenumber for C code and assembly function name for assembler code. Callsites that do not provide callsite information are accumulated into an "unknown" entry.
  • zero - Newly allocated blocks are set 0 instead of being filled with the 0xE7E7xxxxxxxxE7E7 pattern. Setting to 0 helps you to determine whether a callsite is expecting zeroed memory (in which case the allocation request should be followed by memset(pointer, 0, size)).
-showversionJava의 버전과 기본적인 사용법에 대한 정보를 제공한다.
-verbose:<option>Option에 따라 상세 정보를 출력한다. 다음과 같은 옵션이 제공된다.
  • class - Class Loading 정보를 Standard Err에 출력한다. 출력 예는 아래와 같다.
class load: java/io/FilePermission
class load: java/io/FilePermissionCollection
class load: java/security/AllPermission
...
class load: test
class load: test from: file:/C:/Documents/Java_Test/GC%20dump/
  • dynload - Class Loading에 대한 매우 상세한 정보를 제공한다. 클래스명, 클래스 크기, 로딩 시간등의 정보를 포함한다. 출력 예는 아래와 같다.
<  Class size 6594; ROM size 7056; debug size 0> 
<  Read time 128 usec; Load time 126 usec; Translate time 222 usec>
<Loaded java/security/BasicPermissionCollection from c:\IBM\WebSphere\AppServer\java\jre\lib\core.jar>
<  Class size 4143; ROM size 3264; debug size 0>
<  Read time 103 usec; Load time 81 usec; Translate time 117 usec>
<Loaded java/security/Principal from c:\IBM\WebSphere\AppServer\java\jre\lib\core.jar>
<  Class size 239; ROM size 248; debug size 0>
<  Read time 44 usec; Load time 23 usec; Translate time 20 usec>
<Loaded test>
<  Class size 370; ROM size 448; debug size 0>
<  Read time 0 usec; Load time 28 usec; Translate time 39 usec>
  • gc - GC 작업에 대한 정보를 제공한다. 자세한 내용은 GC Dump를 참조한다.
  • jni - JNI 호출에 대한 정보를 제공한다. 출력 예는 아래와 같다.
<JNI ReleaseStringChars: buffer=41EC45B8>
<JNI GetStaticMethodID: gc_dump.main ([Ljava/lang/String;)V>
<JNI GetMethodID: java/lang/reflect/Method.getModifiers ()I>
<JNI GetMethodID: java/lang/String.<init> ([B)V>
<JNI FindClass: java/lang/Object>
<JNI GetMethodID: java/lang/Object.finalize ()V>
<JNI FindClass: java/lang/ref/Reference>
<JNI GetMethodID: java/lang/ref/Reference.enqueueImpl ()Z>
  • sizes - Memory 사용과 관련된 설정값을 출력한다. 출력 예는 아래와 같다.
 -Xmca32K              RAM class segment increment
 -Xmco128K            ROM class segment increment
 -Xmns0K                initial new space size
 -Xmnx0K                maximum new space size
 -Xms4M                 initial memory size
 -Xmos4M               initial old space size
 -Xmox1047608K     maximum old space size
 -Xmx1047608K       memory maximum
 -Xmr16K               remembered set size
 -Xmso32K             OS thread stack size
 -Xiss2K                java thread stack initial size
 -Xssi16K              java thread stack increment
 -Xss256K             java thread stack maximum size
 -Xscmx16M          shared class cache size
  • stacks - Thread 별로 Java/C Stack의 사용 크기를 출력한다. 출력 예는 아래와 같다.
JVMVERB000I Verbose stack: "Thread-1" used 188/3756 bytes on Java/C stacks
JVMVERB000I Verbose stack: "Thread-2" used 516/3756 bytes on Java/C stacks
JVMVERB000I Verbose stack: "main" used 1368/0 bytes on Java/C stacks
JVMVERB000I Verbose stack: "Finalizer thread" used 456/2308 bytes on Java/C stacks
JVMVERB000I Verbose stack: "Gc Slave Thread" used 232/3060 bytes on Java/C stacks

[편집]Non-Standard Options

OptionDefaultDescription
-Xalwaysclassgc-Xclassgc 옵션에 의해 결정됨Global Collection이 발생할 때 Class GC를 수행할 지의 여부를 지정한다. classgc 옵션과 동일한 값이며, Default는 True이다.
-XbootclasspathSun JVM의 bootclasspath 옵션과 동일
-Xcheck:jniFalseSun JVM의 check:jni 옵션과 동일
-XclassgcTrueClassloader가 변했을 때만 Class GC를 수행할 지의 여부를 결정한다.
-Xcodecache<size>OS/Hardware Architecture에 따라 결정됨
-Xcomp-Xjit:count=0 옵션을 사용한 것과 동일. z/OS에서만 사용되며, deprecated 옵션이다.
-XcompactexplicitgcFalseSystem.gc() 호출에 의한 Explicit GC가 발생했을 경우 항상 Compaction을 수행할 지의 여부를 결정한다. Sun Hotspot JVM의 경우에는 System.gc() 호출이 발생할 경우 반드시 Full GC를 수행한다. 반면 IBM JVM의 경우에는 이전 GC 작업에서Compaction이 발생하지 않은 경우에만 Compaction을 수행한다.
-XcompactgcFalseSystem GC나 Global GC가 발생할 때마다 Compaction을 수행한다.
-Xconcurrentbackground1Response Time Collector에서 Concurrent Mark를 수행할 Background Thread의 개수를 지정한다. Concurrent Background Thread는 Application Thread의 성능을 다소 저하시킬 수 있으므로 하나만 구동하는 것이 바람직하다. 단, Concurrent Mark 작업이 잘 진행되지 않아 문제가 생기는 경우에는 이 값을 키우는 것이 해결책이 될 수 있다.
-Xconcurrentlevel<value>
-Xconmeter<option>
-XdisableexcessivegcFalseGC 작업에 지나치게 많은(Excessive) 시간이 소요된 경우에 Out Of Memory Error를 유발하지 않도록 지정한다.
-XdisableexplicitgcFalseSystem.gc() 호출에 의한 GC 작업을 비활성화한다. 이 옵션을 사용하면 System.gc()를 호출하더라도 GC 작업이 발생하지 않는다. RMI에 의한 불필요한 GC 작업이나 사용자의 실수에 의한 강제적인 GC 작업을 방지하고자 하는 목적으로 사용된다.
-XdisablejavadumpFalseJava Dump의 생성을 비활성화시킨다. IBM JVM은 치명적인 Error나 Signal을 받으면 Java Dump를 생성함으로써 사후 문제를 디버깅할 수 있도록 한다. 특정 문제로 인해 지나치게 많은 Dump가 생성될 때 이 옵션을 비활성시키는 경우가 있다.
-XdisablestringconstantgcFalseInterned String에 대한 GC 작업을 비활성화한다.
-XenableexcessivegcTrueGC 작업에 지나치게 많은(Excessive) 시간이 소요된 경우에 Out Of Memory Error를 유발하도록 지정한다.disableexcessivegc와 반대의 역할을 한다.
-XenablestringconstantgcTrueInterned String에 대한 GC 작업을 활성화한다. disablestringconstantgc 옵션과 반대의 역할을 한다.
-Xgcpolicy<option>optthruputGarbage Collector의 종류를 결정한다.
  • optthruput: Throughput Collector를 사용한다. 처리량(Throughput)을 최적화할 목적으로 사용되며, Default Collector이다.
  • optavgpause: Response Time Collector를 사용한다. 응답시간(Response Time)을 최적화할 목적으로 사용된다. GC에 의한 Pause Time을 최소하기 위해 Concurrent Mark/Sweep 작업을 수행한다. Throughput Collector에 비해 처리량으로 다소(5~10%) 떨어진다.
  • gencon: Concurrent Generational Collector를 사용한다. IBM JDK 1.5에서 추가되었다. Sun Hotspot JVM의 CMS Collector와 거의 동일한 방식으로 동작하다.
  • subpool: Subpool Collector를 사용한다.
-Xgcthreads<value>CPU#Throughput Collector는 Mark & Sweep 작업을 Parallel하게, 즉 동시에 여러 Thread를 사용해서 수행한다. 이 옵션을 통해 Parallel GC를 수행할 Thread 수를 지정한다. 기본적으로 CPU 개수를 모두 활용한다. 만일 하나의 Machine에서 여러 JVM을 구동하거나, 다른 종류의 Application과 JVM이 공존하는 경우에는 이 값을 줄임으로써 Context Switching에 의한 성능 저하를 피할 수 있다.
gcworkpackets
int
iss
-Xjit:<options>True(JIT 컴파일을 사용함)JIT 컴파일 옵션을 결정한다. <options>가 지정되지 않으면 단순히 JIT 컴파일을 활성화한다. 이 옵션은 JIT 컴파일러의 버그로 인해 JVM 장애에 대해 Workaround로 많이 활용된다.

JIT 컴파일러의 버그에 의한 JVM Crash가 발생할 경우에는 다음과 같은 유형의 Error Stacktrace가 기록된다.

...
TR_GlobalRegisterAllocator::perform()
TR_OptimizerImpl::performOptimization()
TR_OptimizerImpl::performOptimization()
TR_OptimizerImpl::optimize()
...

이 경우에는 다음과 같은 옵션을 이용해서 JIT 컴파일을 제어할 수 있다.

# Inlining을 비활성화한다.
-Xjit:disableInlining
-Xjit:{java/lang/Math.max(II)I}(disableInlining)

# 특정 메소드를 Optimization에서 제외한다.
-Xjit:exclude={java/lang/Math.max(II)I} ...

아래 옵션들은 JIT 컴파일러에 문제가 발생한 경우 이를 좀 더 쉽제 추적하고자 할 때 사용된다.

count=<n>
   <n>번 째 수행에서 Method를 JIT 컴파일한다. JIT 문제를 추적할 때는 "0"의 값을 사용함으로써 보다 빨리 컴파일이 이루어지도록 한다.    
optlevel=[noOpt | cold | warm | hot | veryHot | scorching]
   [비최적화 ~ 최고 최적화]까지 JIT 컴파일에 의한 최적화 레벨을 지적한다.
verbose
   JIT 컴파일 과정에서 사용된 정보와 컴파일 과정을 출력한다.

아래에 -Xjit:verbose 옵션의 출력 예가 있다. count 값은 1000, optlevel 값은 warm이 기본값임을 알 수 있다.

JIT type: Testarossa (Full)
JIT options specified:
    verbose
options in effect:
    bcount=250
    catchSamplingSizeThreshold=1100
    classLoadPhaseInterval=500
    classLoadPhaseThreshold=155
    code=512 (KB)
    codepad=0 (KB)
    codetotal=0 (KB)
    count=1000
    ...
    stack=256
    target=ia32-win32
    verbose=1
 
+ (warm) java/lang/Double.doubleToRawLongBits(D)J @ 0x41630014-0x41630030
+ (warm) java/lang/System.getEncoding(I)Ljava/lang/String; @ 0x41630054-0x41630145
+ (warm) java/lang/String.hashCode()I @ 0x4163017C-0x4163024A
+ (warm) java/util/HashMap.put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; @ 0x4163027C-0x416304AF
+ (warm) java/util/Locale.toLowerCase(Ljava/lang/String;)Ljava/lang/String; @ 0x416304DC-0x416307FF
...
+ (warm) java/io/FileOutputStream.writeBytes([BIILjava/io/FileDescriptor;)V @ 0x41636C34-0x41636D45|-
loainitial
loamaximum
loaminimum
lp
maxe
maxf
maxt
mca
mco
mine
minf
mint
mn
mns
mnx
mo
moi
mos
mox
mr
mrx
ms
mso
mx
noaot
noclassgc
nocompactexplicitgc
nocompactgc
-XnojitFalseJIT 컴파일 옵션을 사용하지 않는다.
noloa
nopartialcompactgc
nosigcatch
nosigchain
optionsfile
oss
partialcompactgc
quickstart
realtime
rs
runhprof
samplingExpirationTime
scmx
shareclasses
sigcatch
sigchain
softrefthreshold<number>
ss
ssi
thr
verbosegclog:<file>

[편집]BEA JRockit JVM (1.5 기준)

[편집]HP HotSpot JVM (1.5 기준)

[편집]관련 정보

[편집]외부 참조

  1. Sun JVM Option List
  2. Sun JDK 1.6 Full Option List
  3. IBM JVM Command Option
  4. IBM Java AOT Compiler
  5. Fine-tuning IBM JVM Garbage Collector








JAVA(J2SE 1.4.1) 메모리 영역 구조

1. Sun Microsystyems의 자바 HotSpot VM은 힙을 세 개의 영역으로 나누고 있다.

 힙의 세 영역은 다음과 같다:

 1) Permanent space: JVM 클래스와 메소드 개체를 위해 쓰인다.

 2) Old object space: 만들어진지 좀 된 개체들을 위해 쓰인다.

 3) New(young) object space: 새로 생성된 개체들을 위해 쓰인다.

 

 

New object space는 세 부분으로 다시 나누어진. 모든 새로 생성된 개체들이 가는 Eden, 그리고 그 개체들이 나이들게(Old) 되기 전에 가는 Survivor space(From, To) 1 2가 있다.

 

2. Garbage Collector

프로그램은 프로그램을 진행하면서 데이터들을 저장하는 것이 필요하다. 데이터들은 모두 메모리에 저장이 되는데, 저장할 데이터가 있으면 메모리의 일정 공간을 할당받아서 사용하게 된다. 프로그램 내에서 사용하게 되는 메모리를 'heap'이라고 한다. 더 이상 사용되지 않는 데이터에게 메모리를 계속 할당해 주는 것은 메모리를 낭비하는 것이므로, 그 데이터가 사용하던 메모리를 회수하는 것이 필요하다. 이러한 사용되지 않는 메모리에 대한 회수를 'Garbage Collection'이라고 한다. 자바에서는 프로그램이 사용하는 메모리를 JVM(Java Virtual Machine)이 모두 관리한다.

 

3. OutOfMemory Error 및 해결방법

자바는 객체, 변수등의 생성과 동시에 메모리(Heap)를 차지하게 되고, 문제는 이 객체와 변수를 너무 많이 발생시킴으로 해서 현재 할당된 메모리(Heap)를 초과하게 된다

그래서 더이상 할당받을 메모리(Heap)가 부족하게 되면 OutOfMemory Error 발생하게 된다.

OutOfMemory Error 해결방법으로는 jdk1.4에서 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC 옵션을 사용한  GC한 상태의 Heap메모리 정보출력 한다. GC정보를 통하여 New, Old, Perm 등의 영역중 실제 어느 부분이 부족하여 OutOfMemory가 발생하는지 찾은후 부족한 영역의 충분하 size를조절해 주는 방법으로 해결할 수 있다.

 

 

4. Heap layout 할당에 영향을 주는 스위치들

명령행 스위치

설명

-Xms=[n]

최소 heap size

-Xmx=[n]

최대 heap size

-XX:PermSize=[n]

최소 perm size

-XX:MaxPermSize=[n]

최대 perm size

-XX:NewSize=[n] 

최소 new size

-XX:MaxNewSize=[n]

최대 new size

-XX:SurvivorRatio=[n]

New/survivor 영역 비율

-XX:newratio=[n]

Old/new 영역 비율. HotSpot 클라이언트 VM 8, HotSpot 서버 VM 2.

-XX:TargetSurvivorRatio=[n]

GC동안 비울 생존자 수용 가능량 퍼센티지 (capacity percentage.) 초기값은 50%

5. New Generation 메모리 할당 공식

   Eden = NewSize - ((NewSize/(SurvivorRatio + 2)) * 2)

   From space = (NewSize - Eden)/2

   To space = (NewSize - Eden)/2

6. Old Generation 메모리 할당 공식

   Old = Xmx - MaxNewSize

7.  JVM 스위치 설정 예제

  메모리 영역

 Size

설 정

New Generation

Eden

174m

-Xms418m -Xmx418m

-XX:PermSize=1024m 

-XX:MaxPermSize=1024m 

-XX:NewSize=290m 

-XX:MaxNewSize=290m 

-XX:SurvivorRatio=3 

From

58m

To

58m

Old Generation

128m

Permanent Generation

1024m

Total Heap Size

1442m

 1) 현재 http://www.affis.net 서비스는 2200개의 Jsp파일을 가지고 있고 주로 정적이 페이지들이므로      Jsp 파일 로딩에 필요한 Perm size 위주로 메모리 튜닝을 하였다.

 

2) 현재 ·成ʻ成ʻ뤀케 동적이페이지들로 작성되어 있고 어플리      케이션 처리에 필요한  New size 위주로 메모리 튜닝을 하였다.

  메모리 영역

 Size

설 정

New Generation

Eden

534m

-Xms1024m -Xmx1024m

-XX:PermSize=128m 

-XX:MaxPermSize=128m 

-XX:NewSize=800m 

-XX:MaxNewSize=800m 

-XX:SurvivorRatio=4 

From

133m

To

133m

Old Generation

224m

Permanent Generation

128m

Total Heap Size

1052m

 

8. 맺음말

OutOfMemory 발생한다면 GC로그를 찍어본다. 로그를 분석해보면 New(eden, from, to), Old, Perm 등의 영역중에서 GC가 발생해도  메모리 영역이 계속 100%로 할당되는 영역이 보일것이다. 부족한 영역에 충분한 size 메모리를 할당해 주면 OutOfMemory 해결 된다.

그러나 부족한 영역에 계속해서 메모리 할당을 해주어도 사용률이 100%가 나온다면 프로그램 누수일수 있으니 프로그램을 점검해 봐야 할 것이다.



출처 -  http://blog.naver.com/swucs?Redirect=Log&logNo=40011983402 









http://blog.naver.com/inter999?Redirect=Log&logNo=140053719800

 

위 블로그 내용을 보다가 이해 안가는 부분이 두개 있어서 질문 드립니다.

 

첫째

위 내용을 잘 보면

JVM 클래스와 Method 객체가 어느 부분에 들어 가는지 모순 된 설명이 있습니다.

 1.    Method Area1

-       JVM 모든 Thread들이 공유하는 데이터 영역

-       Class 정보, Method 정보, 멤버변수, static 변수 저장 영역

 2.    Heap

-       프로그램 상에서 데이터를 저장하기 위해 동적(실행시간)으로 할당하여 사용하는 영역

-       “new”연산자로 생성된 객체와 배열을 저장

-       주로 실행시간에 생성되는 객체를 저장

-       GC(Garbage Collection)으로 관리 되는 영역

 3.    Java Stack

-       Method 호출될 때마다 스택 프레임이 생성. 이것이 쌓여 스택을 구성.

-       수행되는 Method 정보, 로컬변수, 매개변수, 연산중 발생하는 임시데이터 저장.

-       JVM 스택영역을 실행중인 Thread 따라 각각 구성

 4.    Native Method Stacks

-       Native 메소드를 호출할  native Method 매개변수, 지역변수 등을 저장



을 보면 Method Area에 Class정보와 Method정보가 들어 있다고 나와 있는데 좀 아래쪽을 보면

3.    Permanent Generation

-        JVM 클래스와 Method 객체를 위한 영역



이라고 되어 있네요... Permanent Generation은 Heap에 속하는 영역으로써 GC할때 특정 기준으로 영역을 나누어 놓은 것인데 결국 Class와 Method정보는 Heap에 있다는 내용이 되겠습니다.

그럼 과연 Class정보과 Method정보는 Method Area에 있는 것인가요? 아니면 Heap에 있는 것인가요?

 

둘째

위 첫번째 인용을 보면

1.    Method Area

-       JVM 모든 Thread들이 공유하는 데이터 영역

-       Class 정보, Method 정보, 멤버변수, static 변수 저장 영역

2.    Heap

-       프로그램 상에서 데이터를 저장하기 위해 동적(실행시간)으로 할당하여 사용하는 영역

-       “new”연산자로 생성된 객체와 배열을 저장

-       주로 실행시간에 생성되는 객체를 저장

-       GC(Garbage Collection)으로 관리 되는 영역



와 같이 서술 되어 있는데 static이 아닌 new로 생성된 맴버 변수는 Method Area에 저장되는 것인가요? 아니면 Heap에 저장 되는 것인가요? 전체적인 내용을 보면 Heap에 저장 되는 것으로 보입니다.

맞나요?

 

 

위 두 질문에 답해 주시면 대단히 감사하겠습니다.


답변1

과연 Class정보과 Method정보는 Method Area에 있는 것인가요? 아니면 Heap에 있는 것인가요?

 

-> Class 정보와Method 정보는 Method Area 에 있으나 이것이 객체화  N n =null; 등의 클래스및 변수 객체정의를 통해 객체화 된 내용이  Heap 영역으로 포함됨.

 

static이 아닌 new로 생성된 맴버 변수는 Method Area에 저장되는 것인가요? 아니면 Heap에 저장 되는 것인가요? 전체적인 내용을 보면 Heap에 저장 되는 것으로 보입니다.

맞나요?

 

->new 를 통해 생성된 객체 와 배열이 Heap 에 속하며 변수는 Method Area 에 속합니다.


답변2 
 


Method Area1는 것은 클래스 정의에서 메소드에 해당하는 부분 즉 공통으로 사용되는 부분입니다.

new로 객체를 생성하면 인스턴스를 생성하게 되는데 이때 static 변수를 제외한 나머지 멤버 변수는 모두 heap 에 생성됩니다.

 

출처 - 네이버 지식 

'Development > Java' 카테고리의 다른 글

GC Log 란 ?  (0) 2012.02.02
컨텍스트 리로드(Context reload)  (0) 2012.02.02
Heap dump란?  (0) 2012.02.02
ClassLoader 문제 분석  (0) 2012.02.02
BTrace  (0) 2012.02.02
Posted by linuxism
,

Heap dump란?

Development/Java 2012. 2. 2. 05:34

안녕하세요. 이번에는 Heap dump 분석을 위해 Heap dump가 무엇인지에 대해 알아보도록 하겠습니다.
그럼 Heap dump란 무엇일까요? 
우선 Heap이란 Java에서 사용하는 object들을 저장하는 공간입니다. 물론 Heap이란 용어가 꼭 Java에서만 사용되는 용어는 아닙니다.
Unix에서 Native 즉 C에서 malloc()으로 할당되는 메모리 영역을 Heap(예전에 공부할때 자유저장소 라고도 했었죠 ^^)이라고 말합니다. 물론 Java에서 사용하는 Heap 메모리도 Native 영역의 프로세스 메모리에 생성됩니다.
Java에서 Heap은 Java가 관리하는 별도의 메모리 공간이라고 보면 될 것같습니다. 이후에서 말하는 Heap은 모두 Java Heap을 의미하도록 하겠습니다.
Heap에는 java object 정보만 저장되는 것이 아니고 class 메타 정보 및 각 object들에 대한 참조 정보도 담겨 있습니다.
Heap 메모리에 존재하는 모든 object는 Root 노드부터 시작해서 parent/child 형식의 tree 구조를 형성하고 있습니다. 
이러한 tree 구조는 각 object들의 참조 정보를 통해 이루어집니다. 
tree 구조가 꼭 정형화된 top/down 방식의 구조로만 이루어지지 않고 간혹 역참조에 의해 상호 참조가 발생하기도 합니다.
Heap의 정보를 분석하는 것은 java에서의 메모리 문제(각종 OutOfMemoryError 문제들)를 해결하기 위한 중요한 작업입니다. 
Java가 메모리 사용에 있어서 메모리 할당/해제에 대한 기능을 java가 자체적으로 지원(Garbage Collection)하여 다른 언어(C, C++등) 보다 개발의 편의성을 제공하지만 이에 따른 메모리에 대한 문제점을 항시 내포하고 있는 것이 사실입니다. 
이러한 문제점을 해결하기 위해서 Heap을 분석하는 것이 많은 도움을 줍니다.
각 Java 벤더별로 Heap dump를 생성하는 방법과 그 내용이 조금씩 다른데요. 
크게 IBM 계열과 Sun 계열로 나눌 수 있습니다. 
예를 들어 두 계열의 Heap dump의 가장 큰 차이점은 object에 대한 데이터를 포함하느냐 안하느냐의 차이가 있습니다. Sun 계열을 object에 대한 데이터들을 모두 담고 있으며, IBM 계열은 그렇지 않고 object들에 대한 참조 정보만 담겨 있습니다.

자, 그럼 이러한 Heap dump를 통해 분석할 수 있는 문제점에는 어떤것들이 있을까요 ?
첫번째로 OutOfMemoryError에 대한 문제를 분석하는 것입니다.
Heap dump로 할 수 있는 가장 중요하고도 기본적으로 해결할 수 있는 문제입니다.
두번재로 Permanent Full에 대한 문제 분석입니다.
loaded class의 메타정보들에 대한 정보를 분석하므로써 Permanent Full 문제에 대한 분석이 가능합니다.
물론 Permanent Full도 일종의 OutOfMemoryError라고 할 수 있습니다.
세번째로 메모리 Leak 문제 분석입니다.
메모리 Leak이 지속되면 OutOfMemoryError가 되지만 OutOfMemoryError가 발생하지 않고 많은 메모리를 점유하고 해제되지 않고 있어 GC의 빈도가 잦아져 문제가 발생되는 경우에 Heap dump를 통해 해제되지 않는 object들을 확인할 수 있습니다.
네번째로 기타 Heap과 관련된 문제 분석입니다.
복합적인 원인으로 문제가 발생할 경우 문제 분석을 위한 하나의 정보로서 Heap dump를 활용할 수 있습니다.
예들들어 자원 미해제로 인해 finalizer가 지속적으로 수행되어 CPU 과부하가 발생한 경우입니다.

위와 같은 문제에 대한 분석은 앞으로 차차 사례를 통해 분석 방법을 알아 보도록 하겠습니다.

이제 부터 Heap dump를 어떻게 생성하는지에 대해 Java 계열별로 설명드리도록 하겠습니다.

먼저 Sun Java에서 Heap dump를 생성하는 방법입니다.

다음과 같은 방법으로 Heap dump를 생성할 수 있습니다.
- HPROF 옵션과 함께 JVM을 기동한 경우
- HeapDumpOnOutOfMemoryError 옵션과 함께 JVM을 기동한 경우
- HeapDumpOnCtrlBreak 옵션과 함께 JVM을 기동한 경우
- jmap 명령어를 통한 Heap dump 생성

그럼 위의 경우에 대해 하나씩 알아 보도록 하겠습니다.

- HPROF 옵션과 함께 JVM을 기동한 경우
HPROF는 JVM에서 제공하는 profiling 기능으로 JVMTI(Java Virtual Machine Tool Interface)를 사용하여 JVM과 interface하는 dynamically-linked library 입니다.
HPROF는 profiling 기능을 내재하고 있기 때문에 CPU 사용율, Java heap allocation 상태, monitor contention, thread 상태등에 대한 정보를 제공합니다. 일반적으로 이러한 기능들을 제공하는 툴을 Java Profiler라고 합니다.
실제로 HPROF는 performance, lock contention, memory leak 및 기타 다양한 문제를 분석하는데 효과적으로 활용됩니다. HPROF를 통한 어플리케이션 profiling은 다음 포스트(http://blog.naver.com/bumsukoh/110119532123)를 참고하세요.
HPROF를 설정 위해서는 다음과 같이 java 명령어 옵션을 통해 가능합니다.(Java 1.5 이상 일 경우이며 이하 버전은 별도의 옵션이 필요합니다.)


다음은 HPROF 옵션을 위한 help 부분입니다.


실제 HPROF를 통한 Heap dump 생성 예제는 다음과 같습니다.


- HeapDumpOnOutOfMemoryError 옵션과 함께 JVM을 기동한 경우
이 옵션은 Java 1.5 이상일 경우 사용 가능합니다.
JVM이 Java heap 메모리 또는 permanent 영역의 full로 인해 OutOfMemoryError가 발생할 경우 JVM이 heap dump를 생성하도록 하는 옵션입니다.
이 옵션이 가장 유용한 옵션으로 언제 발생할지 모를 OutOfMemoryError를 대비해서 Heap dump를 생성하도록 하는 옵션입니다. 
이 경우 메모리 문제로 인해 의도적으로 Heap dump를 남기는 경우(HPROF 또는 HeapDumpOnCtrlBreak등)보다 안정적인 운영 상태에서 선택할 수 있는 옵션입니다.
이렇게 생성되는 Heap dump파일은 기본적으로 Java프로세스의 working 디렉토리에 java_pid<pid>.hprof 파일명으로 생성됩니다. (pid는 프로세스 ID임)
생성되는 Heap dump 파일의 위치를 지정하기 위해서는 -XX:HeapDumpPath 옵션을 통해 지정이 가능합니다.
다음은 HeapDumpOnOutOfMemoryError 옵션을 적용한 Java 프로세스 기동 방법입니다.


- HeapDumpOnCtrlBreak 옵션과 함께 JVM을 기동한 경우
이 옵션은 위의 HeapDumpOnOutOfMemoryError와 동일하게 동작하여 Heap dump를 생성합니다.
단, Heap dump가 생성되는 시점의 이벤트가 OutOfMemoryError가 아닌 Ctrl+Break 또는 SIGQUIT Signal에 의해 생성되는 것이 다릅니다.
생성되는 Heap dump파일명은 java_pid<pid>.hprof.<yyyymmdd>.<hhmmss> 파일명으로 생성됩니다.
이 옵션은 window에서는 적용되지 않습니다.
다음은 HeapDumpOnCtrlBreak 옵션을 적용한 Java 프로세스 기동 방법입니다.


다음으로 HP Java에서 Heap dump를 생성하는 방법에 대해 설명드리겠습니다.

HP Java에서는 다음과 같은 방법으로 Heap dump를 생성할 수 있습니다.

- HPROF 옵션과 함께 JVM을 기동한 경우
- HeapDump 옵션과 함께 JVM을 기동한 경우
- HeapDumpOnOutOfMemoryError 옵션과 함게 JVM을 기동한 경우
- HeapDumpOnCtrlBreak 옵션과 함께 JVM을 기동한 경우
- HeapDumpOnly 옵션과 함께 JVM을 기동한 경우

그럼 위의 경우에 대해 하나씩 알아 보도록 하겠습니다.

- HPROF 옵션과 함께 JVM을 기동한 경우
Sun Java에서 설명한 HPROF 동작과 동일합니다. 위의 내용을 참고하시기 바랍니다.

- HeapDump 옵션과 함께 JVM을 기동한 경우
이 옵션은 Java 1.5이상일 경우 사용가능한 옵션입니다. 또한 "_JAVA_HEAPDUMP"라는 shell 환경 변수 설정으로도 동일하게 동작합니다. (예, export _JAVA_HEAPDUMP=1)
Heap dump를 생성하기 위해서는 Java 프로세스에 Ctrl+Break 또는 SIGQUIT Signal을 발생시켜 생성할 수 있습니다. 즉 Thread dump 생성과 동일한 방법입니다.
생성되는 Heap dump 파일은 ASCII 포맷이며, 파일명은 java_<pid>_<time>_heapDump.hprof.txt 형식으로 생성됩니다.
다음은 HeapDump 옵션을 적용한 Java 프로세스 기동 방법입니다.


- HeapDumpOnOutOfMemoryError 옵션과 함께 JVM을 기동한 경우
이 옵션 또한 Java 1.5 이상일 경우 사용가능한 옵션입니다. 
JVM이 Java heap 또는 permanent 영역의 full로 인해 OutOfMemoryError가 발생할 경우 JVM이 Heap dump 파일을 생성하도록 하는 옵션입니다.
이 옵션은 Sun의 HeapDumpOnOutOfMemoryError 옵션과 같은 기능을 제공합니다.(Sun Java HeapDumpOnOutOfMemoryError 참조)

다음은 HeapDumpOnOutOfMemoryError 옵션을 적용한 Java 프로세스 기동 방법입니다.


- HeapDumpOnCtrlBreak 옵션과 함께 JVM을 기동한 경
이 옵션은 위의 HeapDumpOnOutOfMemory와 동일하게 동작하며 Heap dump를 생성합니다.
이 옵션 또한 Sun의 HeapDumpOnCtrlBreak 옵션과 같은 기능을 제공합니다.(Sun Java HeapDumpOnCtrlBreak 참조)
다음은 HeapDumpOnCtrlBreak 옵션을 적용한 Java 프로세스 기동 방법입니다.


- HeapDumpOnly 옵션과 함게 JVM을 기동한 경우
이 옵션 또한 Java 1.5 이상일 경우 사용가능한 옵션입니다.
또한 "_JAVA_HEAPDUMP_ONLY" shell 환경변수 설정으로도 동일하게 동작합니다. (예, export _JAVA_HEAPDUMP_ONLY=1)
Java 프로세스의 SIGVTALRM Signal (signal 넘버 20)에 의해 생성되며, 생성되는 파일의 포맷을 ASCII입니다.
생성되는 파일명은 java_<pid>_<date>_<time>_heapDump.hprof.txt 형식으로 생성됩니다.
다음은 HeapDumpOnly 옵션을 적용한 Java 프로세스 기동 방법입니다.


다음으로 IBM Java에서 Heap dump를 생성하는 방법에 대해 설명드리겠습니다.
IBM Java에서는 다음과 같은 방법으로 Heap dump를 생성할 수 있습니다.
- HPROF 옵션과 함께 JVM을 기동한 경우
- Dump agent 옵션과 함께 JVM을 기동한 경우
- IBM_HEAPDUMP, IBM_HEAP_DUMP shell 환경변수와 함께 JVM을 기동한 경우
- IBM_HEAPDUMP_OUTOFMEMORY shell 환경변수와 함께 JVM을 기동한 경우

자! 그럼 이번에도 위의 경우에 대해 하나씩 알아 보도록 하겠습니다.

- HPROF 옵션과 함께 JVM을 기동한 경우
Sun Java에서 설명한 HPROF 동작과 동일합니다. 위의 내용을 참고하시기 바랍니다.

- Dump agent 옵션과 함께 JVM을 기동한 경우
Dump agent는 JVM에서 발생하는 각종 event (GC, thread start, JVM termination 등) 에 따라 수행되는 기능을 정의할 수 있는 IBM JVM의 기능입니다.
다음은 Dump agent의 종류와 event에 대한 내용입니다. (Dump agent에 대한 자세한 사항은 "IBM Diagnostic" 포스트 내용을 참조하시기 바랍니다.)

Dump agent 종류 확인을 위한 java -Xdump:help 명령 수행 결과입니다.


Dump agent가 지원하는 event 종류를 확인하기 위한 java -Xdump:events 명령 수행 결과입니다.

이러한 Dump agent를 통해 Heap dump를 생성하는 방법과 생성 결과는 다음과 같습니다.




위와 같이 "-Xdump:none" 옵션을 설정하여 전체 dump 옵션을 모두 ignore 시킵니다.
그리고 "-Xdump:heap:events=vmstop,opts=PHD+CLASSIC" 옵션을 통해 heap dump를 생성하는데, vmstop(JVM이 down될 경우) event가 발생할 경우 PHD 포맷과 CLASSIC 포맷(TEXT 포맷)으로 heap dump를 생성하게 됩니다.

- IBM_HEAPDUMP, IBM_HEAP_DUMP shell 환경변수와 함께 JVM을 기동한 경우
IBM_HEAPDUMP, IBM_HEAP_DUMP shell 환경변수를 TRUE로 설정한 상태에서 JVM을 기동한 경우 crash나 user signal을 통해 heap dump를 생성할 수 있습니다. 
물론 이러한 shell 환경변수를 설정하게 되면 내부적으로 Dump agent의 heap dump 생성 옵션이 설정되는 것입니다.
이렇게 설정한 경우 heap dump를 생성하기 위해 Ctrl+Break 또는 SIGQUIT signal을 사용하게 됩니다. 이 경우 javacore 파일과 같이 생성되게 됩니다.
이렇게 생성된 heap dump 파일은 바이너리 포맷(PHD)으로 생성됩니다. 
또한 IBM_HEAPDUMPDIR shell 환경변수를 설정하여 heap dump파일이 생성되는 위치도 지정이 가능합니다.
생성된 heap dump 파일의 파일명은 heapdump.<YYYYMMDD>.<HHMISS>.<pid>.<순번>.phd 로 생성됩니다.

다음은 shell 환경 변수 설정 예입니다.


- IBM_HEAPDUMP_OUTOFMEMORY shell 환경변수와 함께 JVM을 기동한 경우
IBM_HEAPDUMPOUTOFMEMORY shell 환경변수를 TRUE로 설정한 상태에서 JVM을 기동한 경우 OutOfMemoryError가 발생할 경우 heap dump가 생성됩니다.
이렇게 생성된 heap dump 파일은 바이너리 포맷(PHD)으로 생성됩니다.

다음은 shell 환경 변수 설정 예입니다.


지금까지 Heap dump란 무엇이며, Sun/HP/IBM Java에서 Heap dump를 생성하는 방법에 대해 알아 보았습니다.
다음 시간에는 Heap dump에 무슨 내용이 어떻게 들어 있는지 알아보도록 하겠습니다.
그럼 즐거운 시간되세요. ^

출처 -  http://blog.naver.com/bumsukoh?Redirect=Log&logNo=110123438564&from=postView 


Posted by linuxism
,

A class loader is an object that is responsible for loading classes.
이 구문은 JDK API 문서 중 ClassLoader에 대한 부분 중 가장 먼저 나오는 구문입니다.
이 구문과 같이 ClassLoader는 Java class들의 loading 기능을 담당하는 class 입니다.
이번 포스트에서는 모든 class에 대해 instance를 생성해 주는 ClassLoader에 대해 알아보도록 하겠습니다.

위의 문구에서와 같이 모든 class는 ClassLoader를 통하게 되는데요. 이는 Java에서 class는 ClassLoader를 통해 물리적인 class파일을 JVM으로 loading하게 됩니다.
또한 ClassLoader는 class를 JVM으로 loading 하기 위해서 정해진 경로(흔히 classpath임)에서 해당 class 파일을 찾아 loaging 작업을 수행하게 됩니다.
이때 ClassLoader는 class 파일이 structurally well-formed 여부를 확인하는 작업 및 보안 관련된 작업을 수행하게 됩니다.
물론 Custom ClassLoader를 통해 더 많은 작업을 수행할 수도 있습니다.
Java에서 기본적으로 제공하는 ClassLoader를 상속받아 다양한 Custom ClassLoader를 생성할 수 있는데요.
이러한 Custom ClassLoader를 통해 구현한 대표적인 기능 중의 하나가 Hot-Deploy라 할 수 있습니다. 
Java 프로세스에서의 Hot-Deploy는 프로세스의 재기동 없이 변경된 모듈을 적용하는 기능입니다.
이러한 기능은 Custom ClassLoader내에 변경 여부를 확인하는 로직과 변경 시 재로딩하기 위한 기능이 구현되어 있는 것이라고 할 수 있습니다.
Custom ClassLoader를 사용하게 되면 class 로딩 시점에 다양한 기능을 구현하고 활용할 수 있습니다.
예를 들어 loading하고자 하는 class 파일이 없거나 소스 파일이 변경되었을 경우 해당 소스파일을 찾아 컴파일한 후 class파일을 loading하는 기능(jsp의 Hot-Deploy 기능과 유사)을 구현할 수도 있습니다.

그럼 Custom ClassLoader가 작동하는 방식에 대한 설명을 WAS의 jsp 모듈을 로딩 및 실행하는 경우를 통해 설명드리겠습니다.


위의 그림과 같이 사용자의 jsp 처리 요청이 발생할 경우 처리 Thread들이 해당 요청을 처리하기 위해 할당되며, 
해당 Thread가 jsp에 대한 instance의 loading 일자와 실제 물리적인 jsp 파일의 변경 일자를 비교하게 됩니다. 
비교결과 파일이 변경되었다면 변경된 jsp 파일을 읽어들여 .java 파일로 변경하고 class로 컴파일 하게됩니다.
컴파일된 class 파일을 instance화하여 구버전의 instance와 바꿔치기를 수행합니다. 이렇게 되면 사용자 요청은 변경된 jsp 모듈을 수행할 수 있게 됩니다.

그럼 ClassLoader에 대해 본격적으로 설명드리기 전에 Java 프로그램(JVM)의 LifeCycle에 대해 알아보고, ClassLoader가 어느 부분에서 관여가 되는지를 확인해 보도록 하겠습니다.


위의 그림과 같이 Java 프로그램이 실행될 때는 JVM Start-up, Loading, Linkig(Verification, Preparation, Resolution), Initialization, New class creation, Finalization, Unloading, JVM Exit 단계의 Life Cycle을 가지게 됩니다.
이 중 ClassLoader가 관여하는 단계는 JVM Start-up, Loading, Linking, Initialization, New class instance creation 부분이 되겠습니다.

그럼 이제 본격적으로 ClassLoader에 대해 알아보기위해 ClassLoader가 class를 loading하기 위한 내부동작(Method 단위) 방식에 대해 알아 보도록 하겠습니다.


위의 그림과 같이 ClassLoader는 Parent/Child 형식의 계층 구조를 가지게 됩니다. 그리고 이러한 계층 구조를 통해 load된 class 및 load할 class들을 찾게 됩니다.
시스템 운영중에 발생할 수 있는 각종 ClassLoader와 관련된 문제들이 이러한 계층 구조에서 비롯된다고 할 수 있습니다.
예를 들어 class를 찾지 못하는 문제같은 경우는 계층 구조의 어느 ClassLoader에서 class를 load했느냐와 해당 ClassLoader가 어떤 classpath를 가지고 있느냐에 깊은 연관이 있습니다.

ClassLoader는 class를 load하기 위해 각종 수행해야 하는 절차와 관련된 메소드들이 있습니다.
가장 먼저 class를 load하기 위해 수행되는 메소드는 loadClass()입니다. 이는 class를 instance하기 위한 class의 메타 정보를 찾기 위해 가장 첫번째로 수행하는 메소드입니다.
그 다음으로 findLoadedClass()가 수행이 되는데요. 이 메소드는 이름과 같이 load할 class가 현재 load 되어 있는지의 여부를 확인하는 역할을 합니다.
findLoadedClass() 에서 load할 class가 이미 load된 상태라면 바로 return되고 해당 class 메타 정보를 이용하여 instance가 생성됩니다.
그러나 load할 class가 load가 되지 않았다면 ClassLoader는 parent의 loadClass()를 호출하게 됩니다.
parent ClassLoader는 child ClassLoader가 했던것처럼 loadClass()에서 findLoadedClass() 메소드를 호출하여 load할 class가 현재 ClassLoader에 load되어 있는지 여부를 확인합니다.
child ClassLoader와 똑같이 load할 class가 이미 load된 상태라면 바로 return되고 해당 class의 instance가 생성됩니다.
그러나 이번에도 찾고자 하는 class가 load되지 않았다면 ClassLoader는 또 다른 parent ClassLoader의 loadClass()를 호출하게 됩니다.
이때 더이상 parent ClassLoader가 존재하지 않는다면 findBootstrapClass() 메소드가 호출되어 Bootstrap ClassLoader의 findBootstrapClass()가 호출되어 Bootstrap ClassLoader에서 load할 class를 찾게 됩니다.
이러한 방식으로 load할 class가 이미 load되어 있다면 load된 class 메타 정보로 해당 class의 instance를 생성하게 됩니다.
그런데 load할 class가 모든 ClassLoader상에서 load되어 있지 않다면 최상위 ClassLoader(Bootstrap ClassLoader)에서 부터 class파일을 load하기 위해 classpath의 경로에서 물리적인 class 파일을 찾게됩니다.
최상위 ClassLoader에서 classpath상에서 class를 못찾게되면 다음 child ClassLoader에서 찾게되면 그렇게 찾아 내려오다 class가 찾아 지는 ClassLoader에서 class가 load됩니다.
만약 모든 ClassLoader상에서 물리적인 class파일을 못찾게 되면 ClassNotFoundException 이 발생하게 됩니다.

자! 그럼 ClassLoader의 가장 핵심인 loadClass() 메소드에 대해 살펴보도록 하겠습니다.


위의 그림과 같이 ClassLoader의 loadClass()에는 위에서 제가 복잡하고 장대하게(??) 설명한 내용이 몇줄로 구현되어 있습니다.
보시면 별 무리없이 이해하시리라 생각됩니다.

그럼 여기서 앞쪽에 잠깐 언급했던 ClassLoader의 계층구조에 대해 살펴보도록 하겠습니다.
이러한 계층구조로 인해 class를 찾지 못하거나 변경이 발생하지 않는 경우가 실제로 발생하는 사례들이 많이 있습니다.


위의 그림은 Java에서 사용되는 일반적인 ClassLoader의 계층구조입니다.
사용하는 환경에 따라 조금씩 다를수는 있지만 거의 표준적으로 위와 같은 구조를 가지고 있습니다.
가장 상위부터 Bootstrap ClassLoader -> Extensions ClassLoader -> Application ClassLoader -> Custom ClassLoader 순의 계층으로 구성됩니다. 좌측의 화살표는 class를  loading하기 위해 class파일을 찾는 순서입니다.
각 계층별로 동일한 package의 class파일이 있다면 가장 상위의 ClassLoader에 의해 class파일이 load됩니다.

다음은 ClassLoader의 계층 구조를 확인하기 위한 간단한 코드와 여러 환경에서 수행한 결과입니다.


위의 코드는 현재 Thread의 ClassLoader와 그 parent의 ClassLoader들을 계속 출력하는 것이며, 그리고 이 프로그램을 일반 어플리케이션과 일부 WAS에서 jsp로 수행한 결과입니다. 
ExtClassLoader와 AppClassLoader는 Java Vendor에게 제공하는 기본 ClassLoader이며 그 상위로는 각 WAS 벤더별로 Custom ClassLoader가 구현(StandardClassLoader나 ChangeAwareClassLoader 등)되어 있는 것을 알 수 있습니다.

이러한 ClassLoader로 인해 발생하는 문제에 대해 확인해 보고 예제를 통해 해결하는 방법을 알아 보도록 하겠습니다.
먼저 ClassNotFoundException이 발생하는 경우입니다.
ClassNotFoundException은 load할 class를 ClassLoader가 찾지 못할 경우 발생합니다. 이 오류는 ClassLoader와 관련하여 가장 많이 발생하는 문제입니다. 이 문제는 손쉽게 해결되는 경우도 있지만 간혹 해결에 어려움을 겪기도 합니다.

다음으로는 변경된 class가 반영되지 않을 경우입니다.
이 경우는 class를 변경하여 저장한 후 프로그램을 재수행했을때 프로그램 수행에는 문제가 없지만 변경된 내용이 반영되지 않고 기존의 class가 수행되는 것입니다.
이것은 대부분 잘못된 class 파일 관리 정책으로 인해 발생하는 경우가 많으며, 계층적으로 이루어진 ClassLoader상에서 잘못된 경로에 class 파일들이 위치할 경우에 발생할 수 있습니다.

다음으로는 Heap 중 Permanent 영역의 Full이 발생하는 경우입니다.
이 경우는 class의 메타 정보를 저정하는 Permanent 영역이 정상적으로 해제되지 않고 지속적으로 증가하여 Permanent 영역의 부족으로 OutOfMemoryError가 발생하는 경우입니다.
Custom ClassLoader의 잘못된 구현으로 발생할 수도 있으나, class간의 관계에서 참조값이 해제되지 않아 발생하는 경우가 많습니다. 또는 Permanent 영역이 실제 사용하는 class 크기보다 작게 설정되어 발생할 수도 있습니다.

다음으로는 NoClassDefFoundError가 발생하는 경우입니다.
이 경우는 class 파일이 잘못된 구조(malformed)로 인해 발생하는 문제이며, 보통 쉽게 해결되는 문제입니다.

그럼 ClassNotFoundException이 발생하는 문제를 예제를 통해 분석해 보도록 하겠습니다.
이번 예제는 EJB와 Web Application 간의 ClassLoader 관계로 인해 발생하는 ClassNotFoundException에 대한 문제입니다.
일부 WAS들은 class 공유를 위해 ClassLoader에 두가지 mode로 운영할 수 있는 기능을 제공합니다.
두가지 mode는 다음과 같습니다.


위의 그림과 같이 SHARED와 ISOLATED로 두가지 mode가 있으며 두 mode는 ClassLoader의 계층구조가 다른 것을 알 수 있습니다.
SHARED  모드일 경우는 Servlet ClassLoader의 class들이 EJB ClassLoader의 class를 참조할 수 있는 장점이 있으나 ClassLoader 간의 class 공유로 인한 구성의 복잡성 문제가 발생할 수 있습니다.
그에 비해 ISOLATED 모드는 Servlet ClassLoader와 EBJ ClassLoader간에 class들의 공유되지 않아 class 참고를 위해 중복 배포해야 하는 관리의 어려움이 있습니다. 예를 들어 EJB의 Remote Interface class를 servlet에서 참조하기 위해 Servlet ClassLoader가 access되는 위치에 배포해야 합니다.
그러나 독립성이 보장된다는 장점으로 ISOLATED 모드가 요즘은 대세인 분위기 입니다.

다음은 변경된 class가 반영되지 않는 문제를 예제를 통해 분석해 보도록 하겠습니다.
이 경우는 잘못된 class 파일 관리 정책으로  인해 ClassLoader의 경로 상에 의도한 경로 외에 다른 경로의 class가 사용되는 경우라 할 수 있습니다.
이러한 문제에 대한 예제는 아래 그림에서와 같습니다.


위의 그림과 같이 동일한 class 파일이 Application ClassLoader의 classpath와 Servlet ClassLoader의 WEB-INF/classes 내에 같이 존재할 경우 class는 Application ClassLoader의 class가 반영됩니다.
그러나 실제 class들이 사용되는 것이 servlet 이여서 Servlet ClassLoader의 WEB-INF/classes에 변경하여 저장하더라도 해당 class가 반영되지 않는 문제가 발생합니다.
이 경우 관리자가 class들의 사용 용도와 레벨을 정하여 정확한 위치에 배포하는 정책이 필요합니다.
다음은 class가 load된 위치를 확인할 수 있는 간단한 프로그램입니다. 실제 어디에 있는 class인지를 확인할 수 있는 유용한 프로그램입니다.


다음은 Permanent 영역의 Full로 인해 발생하는 문제를 예제를 통해 분석해 보도록 하겠습니다.
이 부분은 이미 Heapdump 분석 포스트에서 이미 언급한 부분이여서 해당 포스트(http://blog.naver.com/bumsukoh/110125469644)를 참고하시기 바랍니다.

다음은 NoClassDefFoundError가 발생하는 문제에 대해 예제를 통해 분석해 보도록 하겠습니다.
이 문제는 대부분 class의 잘못된 구조로 인해 발생하는 문제이며 대부분 재컴파일을 통해 class를 재생성하게 되면 해결되는 문제들입니다.
아래 그림은 class 이름을 임의로 변경하여 발생하는 NoClassDefFoundError의 예제입니다.


위의 그림과 같이 class이름을 임의로 변경 후 프로그램을 수행한 결과 NoClassDefFoundError가 발생하는 것을 알 수 있습니다.
재컴파일 후에 프로그램을 재수행하면 다시 정상적으로 동작하게 됩니다.

지금까지 ClassLoader에 대한 설명과 발생 가능한 문제점 및 해결 방법을 알아 보았습니다.
다음 시간에는 이번 트러블슈팅 가이드 시리즈의 마지막 포스트인 JNI 문제 분석에 대해 설명드리도록 하겠습니다.
다들 다음 포스트때 가지 즐거운 시간 되시기 바랍니다.


출처 -  http://blog.naver.com/bumsukoh?Redirect=Log&logNo=110127431857&from=postView

'Development > Java' 카테고리의 다른 글

java - JVM 메모리 및 옵션  (0) 2012.02.02
Heap dump란?  (0) 2012.02.02
BTrace  (0) 2012.02.02
jstat 유틸을 이용하면 JVM상태를 상세하게 모니터링 할 수 있다.  (0) 2012.02.02
java.lang.OutOfMemoryError: PermGen space  (0) 2012.02.02
Posted by linuxism
,