堆内存和设置GC

JVM通过Ergonomics技术已经尽可能的让jvm不要我们去操心底层的细节,而尝试提供给我们好的服务。
但是,内存管理和gc并没有一个一劳永逸的方案。
GC有可能成为性能的瓶颈。很多时候还是要程序员自己动手去做一些调优。
以下简要介绍一些关键概念。

JVM会自动选择使用server mode还是client mode。但是我们一样可以手工设置。
java -server -client

JVM的内存管理分为堆内存(Heap Memory)和非堆内存。
Heap Memory用来存储大部分对象。
非堆内存=Code Cache+Permanent Generation。
其中Code Cache用于编译和保存本地代码(native code)的内存
Permanent Generation保存虚拟机自己的静态(refective)数据,例如类(class)和方法(method)对象。

经过统计,大部分的内存垃圾都是刚刚new出来的对象产生的,于是,Heap Memory的内存管理是分代的。
JVM的堆内存划分为Young和Tenured。Young里面有1个Eden和2个Survivor,其中一个Survivor永远为空。
按照代的从新到老的顺序:Eden,Survivor,Tenured.

Heap Memory=Eden space+ 2个Survivor space+Tenured space。

为什么Survivor有两个呢.
其中一个一直为空.
大部分对象的分配是在Eden中进行的。当进行一次gc时,可以把Eden和Survivor中的live object复制到那个空的Survivor.

可以用设置标志来查看gc的运行情况.(-verbose:gc)
这个会在console中打出如下信息
[GC 325407K->83000K(776768K), 0.2300771 secs]

GC代表这是一次Minor collection,只回收Young中的对象。
Full GC代表一次Major collection,回收Tenured。

和gc相关的性能指标

Throughput 程序真正运行时间/(程序真正运行时间+GC时间)
Pauses GC导致的程序暂停时间

常见的GC,有多种GC可供我们选择.

serial collector:
单线程GC.

parallel collector:
并行GC,多线程,如果机器是多核的比较适合.
传统的parallel collector同时只能有一个线程作Major collection.
可以引入parallel compaction,多个线程并行做Major collection.

concurrent collector:
该GC大部分的工作都是和程序并行完成的,所以Pauses的时间比较少.


如何设置GC.

0 大部分情况不用调用gc,让jvm自己做好了.
1 任何时候都是让jvm先自己选择gc,当性能有问题的时候再手工调.
2 当有Pauses时间要求的时候,尝试concurrent gc.
3 当没有Pauses时间要求时,尝试parallel collector.
4 合理的设置gc的其他参数以及堆的其他参数.
5 不要迷信任何主观的想法,一定要测试,比较,修改,测试,比较,修改...的坐下去,直到性能在合理的期望中.
6 server mode时内存的划分反向了,用jsonsole可以观察到,设置参数时需要注意.

你可能感兴趣的:(jvm,多线程,虚拟机,工作,cache)