@xtccc
2018-05-15T16:56:10.000000Z
字数 4673
阅读 3958
Java
参考:
好文
本文内容针对Java 8
如果把-Xms
搞得太大,达到了系统的极限,Java进程会被kernel Kill。如果时通过控制台启动的Java进程,会在console上看到:
Java进程直接被kernel杀掉,因此,即使设置了-XX:ErrorFile
或者-XX:+HeapDumpOnOutOfMemoryError
之类的选项,你也不会看到error文件的生成。
通过dmesg
命令,可以看到kernel的信息,例如:
也可能看到如下的输出:
参考 Who “Killed” my process and why?
-Xmx
应该根据实际的需求来设置,而不是越大越好。如果设置地过大,可能反而导致throughput变低,或者latency变高。
有些优化选项伴随着某方面的代价,开启后会造成性能下降。
例如,当使用G1 collector时,如果使用了-XX:+UseStringDeduplication
,那么throughput会显著地降低
紫框的3个部分就是对性能影响最大的3个部分。
GC调优,就是:
JIT compiler对Java App的性能也有很大影响,但是它极少需要去调优。
GC的目的是:在Heap中识别哪些object是有用的,哪些是没用的。无用objects,就是那些没有被程序的任何部分引用(referenced)的objects。unreferenced objects将要被删除,它们占据的heap空间将被释放。
GC的过程可以分为以下几个步骤:
以上的三个步骤都是相对耗时的操作,根据“大部分的objects都是短命鬼”的经验,JVM将heap划分成了3个部分:
Young Generation
新的objects都被分配年轻代,然后它们逐渐老去。当年轻代被占满了之后,会触发一次minor garbage collection(这是一个stop-the-world event)。
Old / Tenured Generation
年轻代里面幸存下来objects,会被移动到老年代里面。当老年代被占满了之后,会出发一次major garbage collection(也是stop-the-world event)。major gc往往比较慢,因为它涉及到了所有长寿的对象。
Permenant Generation
这里保存的是JVM的metadata,例如library classes, methods.
在单核机器上,只能使用默认的Serial Collector: -XX:+UseSerialGC
在多核机器上,则可以使用Parallel Collector (又称为throughput collector)。有多种Parallel collectors可以使用。
"-XX:+UseParallelGC"
这个设置,会对young generation使用multi-thread collector,而对old generation则仍然使用single-thread collector及single-thread compaction
"-XX:+UseParallelOldGC"
这个设置,会对young generation collection、old generation collection以及old generation compaction都使用multi-thread collector。
"-XX:+UseConcMarkSweepGC"
这个设置,将会对old generation使用Concurrent Mark Sweep (CMS) Collector,而对young generation则仍然使用原来的parallel collector。CMS的特点是low pause,因为它不会进行compaction(即不会移动live objects),因此heap fragments可能会是一个问题。在这种情况下,需要使用更大的heap。
CMS Collector将被G1 Collector代替,下面会讲。
"-XX:+UseG1GC"
G1 collector is a parallel, concurrent, and incrementally compacting low-pause garbage collector.
以下述仅适用于serial, stop-the-world(non-parallel) collectors,参考 Sizing the Generations。
At initialization of the virtual machine, the entire space for the heap is reserved. The size of the space reserved can be specified with the -Xmx
option. If the value of the -Xms
parameter is smaller than the value of the -Xmx
parameter, than not all of the space that is reserved is immediately committed to the virtual machine. The uncommitted space is labeled "virtual" in the following figure. The different parts of the heap (tenured generation and young generation) can grow to the limit of the virtual space as needed.(两头向中间发展)
对于
如果指定了-XX:+PrintGCDetails -Xloggc:${RootDir}/akka/logs/worker-gc.log
,则可以将GC log输出到文件中。为了防止输出的文件太大,还可以继续加入参数-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=10M
。
GC log里面的内容形如:
G1 Collector输出的GC log则比较特殊:
我们可以通过一些工具来分析这些log,并且找出哪里是瓶颈。GCeasy就是这样的一个工具,在网站上我们把GC log文件上传,然后它就会分析,并且指出可疑之处。
GC pause time可以显著降低,
同一段代码和同一份数据,使用-XX:UseParallelOldGC
时,max gc pause time ≈ 4秒;换成-XX:UseG1GC
,则max gc pause time ≈ 0.4秒
因此, G1适合于对响应时间要求高的应用。如果跑batch计算,G1就不合适。
Useful JVM Flags – Part 7 (CMS Collector)
一般来说,CMS GC一般比其他parallel GC更快,特别是full GC更快。但是当concurrent mode failure发生时,CMS GC比其他parallel GC要慢。
CMS GC与Parallel GC的区别在于compaction. Parallel GC会在发生Full GC时,同时发生compaction。CMS GC则不会立即进行compaction。
因此,CMS GC不会立即对内存碎片进行清理,而是等到无法再分配新内存时(i.e., concurrent mode failure)再进行compaction然后再试图分配内存。