前段时间又看了一遍《深入理解Java虚拟机》,感觉比以前看的理解程度多了一些。找一些以前的关于虚拟机参数的笔记内容写下来。
虚拟机有很多种,一般应用的都是HotSpot虚拟机,所以大家讨论的也都是针对这款虚拟机。不同的虚拟机实现是不一样的。
运行时会根据热点程序,进行不同程度的优化编译,不是编译一次就完事的。高级编译时会引入大胆的优化策略,也会留逃生门。
一,注意事项
- 虚拟机在64位机器上,内存大于32G时,会放弃指针压缩,导致内存很大浪费,所以内存最好控制在4-32G。
- 使用Jinfo观察运行时的所有参数;
- jstack查看线程信息;jmap生成dump文件;jstat观察运行时的类加载、编译、回收内容。
- 使用MAT可视化分析线上Dump文件。由于文件一般比较大,所以分析时比较耗内存,也比较慢。
- 出现内存溢出的问题时,仔细看一下报错内容,在不同区域内存报错的类型或提示是不一样的。
二,垃圾收集器
- 目前HotSpot使用的是分代收集法。相关策略有Serial、ParNew、Parallel、CMS、G1等等。
- NewRatio参数设置新生代和老生代的内存比例。
- 新生代Eden和Survivor的默认比例是8:1,即SurvivorRatio为1。
- Windows和Linux(CPU只有一个核)时,JVM默认运行的模式是Client,此时默认的收集器是Serial;在Linux多核时默认运行的模式是Server,收集器使用的是Parallel。
- 可通过-XX:Use***GC来修改收集器类型,不同的收集器类型还有详细的相关参数进行微调。
- 在服务器上,使用CMS已经非常成熟了,很多中间件都是使用的CMS回收。
三,其他参数
- HeapDumpOnOutOfMemoryError和HeapDumpPath参数,用以在发生OOM异常时保存当时Dump。
- PrintGC和PrintGC***参数可以在每次垃圾回收时输出日志,包含回收各部分内存大小和消耗时间。
- 一般新生代的收集时间为几毫秒,老生代的回收时间达到一百多毫秒。异常状况时,数值会变大很多。
四,收集器微调
1. SerialGC :
-XX:+UseSerialGC
就是Young区和old区都使用serial 垃圾回收算法。
2. ParNewGC
-XX:+UseParNewGC
设置年轻代为多线程收集。可与CMS收集同时使用。在serial基础上实现的多线程收集器。
指定在 New Generation 使用 parallel collector, 是 UseParallelGC 的 gc 的升级版本 , 有更好的性能或者优点。
-XX:ParallelGCThreads 限制线程数量
3. ParallelGC
-XX:+UseParallelGC
选择垃圾收集器为并行收集器。此配置仅对年轻代有效。可以同时并行多个垃圾收集线程,但此时用户线程必须停止。新生代使用parallel并行收集,会暂停app threads,同时启动多个垃圾回收thread。不能和CMS一起使用。一般来说后台系统任务使用此方式。
4. CMS
-XX:+UseConcMarkSweepGC
Young区:可以使用普通的或者parallel 垃圾回收算法,由参数 -XX:+UseParNewGC来控制。Old 区:使用CMS
-XX:CMSInitiatingOccupancyFraction=75
这个值指定了老生代使用到成么程度后进行回收。
-XX:+UseCMSInitiatingOccupancyOnly
如果没有使用此参数,那么HotSpot VM只是利用上述参数值来启动第一次CMS垃圾回收,后面都是使用HotSpot VM自动计算出来的值。
-XX:+ UseCMSCompactAtFullCollection Full GC后,进行一次碎片整理;整理过程是独占的,会引起停顿时间变长
-XX:+CMSFullGCsBeforeCompaction 设置进行几次Full GC后,进行一次碎片整理
-XX:ParallelCMSThreads 设定CMS的线程数量