JVM碎碎念

前言

  HotSpot VM 作为使用最广泛的 JVM 的,如无歧义,以下谈到 JVM 均指代 HotSpot VM。

TLAB

  堆区是线程共享区域,线程在创建新对象时需要在堆中开辟内存。然而在并发的情况下从堆中申请内存并不安全,为了避免多个线程同时操作同一个地址,需要互斥锁等同步机制来保证安全,但这会影响内存分配效率,因而引入了TLAB这个概念。

  • 从内存模型而不是垃圾收集的角度,对Eden继续进行划分,JVM为每个线程分配了一个私有缓冲区,它包含在Eden空间内
  • 多线程同时分配内存时,使用TLAB可以避免一系列的线程不安全问题,同时因为不需要同步机制从而有效的提高了内存分配吞吐量

一旦对象在TLAB中分配失败(默认情况下TLAB仅占Eden空间的1%,容量非常小),JVM会尝试通过锁机制来确保内存分配的原子性,从而直接在Eden中分配内存。可以通过JVM参数-XX:UseTLAB开启TLAB支持(默认开启),注意引入了TLAB之后,可以说堆就不是100%线程共享的了。

启动参数

分类

> $ java -jar -server -Dfile.encoding=UTF-8 -Xmx8g -XX:+UseG1GC -XX:MetaspaceSize=512m demo.jar
  1. -开头的是标准参数,所有的 JVM 实现都要支持这些参数,并且向后兼容
  2. -D开头的是系统参数,可以在代码中通过System.getProperty(String key)来获取
  3. -X开头的是非标准参数,基本都是传给 JVM 的。注意不是所有的 JVM 实现都支持,并且不保证向后兼容。可以使用java -X命令来查看当前 JVM 支持的非标准参数
  4. –XX开头的是非稳定参数,用于控制 JVM 的行为,跟具体的 JVM 实现有关,并且随时可能会在下个版本取消
    • -XX:+-flag形式,+- 表示开启或关闭某个功能
    • -XX:key=value形式, 指定某个选项的值

常见参数

运行模式
  • -Xint: 在解释模式下运行,-Xint 标记会强制 JVM 解释执行所有的字节码。这当然会降低运行速度,通常低10倍或更多
  • -Xcomp: -Xcomp 与 -Xint 正好相反,JVM 在第一次使用时会把所有的字节码编译成本地代码,从而带来最大程度的优化
  • -Xmixed:-Xmixed 是混合模式,将解释模式和编译模式进行混合使用(由 JVM 自己决定),这是 JVM 的默认模式,也是推荐模式。 可以使用 java -version 查看 mixed mode 等信息
内存设置
  • -Xmx,指定最大堆内存,默认物理内存/4。注意此参数只是限制了 新生代+老年代 的最大值,不包括栈内存,也不包括堆外内存
  • -Xms,指定起始堆内存,默认物理内存/64。 注意此参数指定的内存大小,并不是操作系统实际分配的初始值,而是GC先规划好,用到才分配。 建议服务器上保持 –Xms 和 –Xmx 一致,避免因堆内存扩容导致的性能抖动以及FullGC
  • -XX:NewSize=,指定新生代起始容量
  • -XX:MaxNewSize=,指定新生代最大容量
  • -Xmn,指定新生代大小,等价于同时设置 -XX:NewSize=-XX:MaxNewSize=,使用 G1 垃圾收集器不应该设置该选项,官方建议设置为 -Xmx 的 1/4 ~ 1/2
  • -XX:NewRatio=,指定老年代与新生代的比例,默认2,与 -Xmn 互斥
  • -XX:SuriviorRatio=,指定年轻代中Eden区与单个Survivor区的比例,默认8
  • -XX:PermSize=,指定永久代起始容量, JDK1.8 前使用
  • -XX:MaxPermSize=,指定永久代最大容量, JDK1.8 前使用
  • -XX:MetaspaceSize=,指定元空间起始容量,默认 -1 不限制,JDK1.8 后使用
  • -XX:MaxMetaspaceSize=,指定元空间最大容量,Java 8 默认不限制 Meta 空间,最好不要设置该选项
  • -XX:MaxDirectMemorySize=,指定最大堆外内存,这个参数和 -Dsun.nio.MaxDirectMemorySize 效果相同
  • -Xss,指定线程栈大小,影响栈的深度,如 -Xss1m 指定线程栈为 1MB,与 -XX:ThreadStackSize=1m 等价
GC相关
  • -XX:+UseG1GC,使用 G1 垃圾回收器
  • -XX:+UseConcMarkSweepGC,使用 CMS 垃圾回收器,ParNew + CMS,关注响应时间
  • -XX:+UseSerialGC,使用串行垃圾回收器 ,Serial + SerialOld
  • -XX:+UseParallelGC,使用并行垃圾回收器,Parallel + ParallelOld,关注吞吐量(java 7~8默认)
  • -XX:+PrintGC,输出GC日志
  • -XX:+PrintGCDetails,输出GC的详细日志
  • -XX:+PrintGCTimeStamps,输出GC的时间戳(以基准时间的形式)
  • -XX:+PrintGCDateStamps,输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
  • -XX:+PrintHeapAtGC,在进行GC的前后打印出堆的信息
  • -Xloggc: ,日志文件的输出路径
  • -XX:MaxTenuringThreshold=,晋升老年代的年龄阈值,使用 SerialGC、ParNew 时有效
  • -XX:PretenureSizeThreshold,晋升老年代的大小阈值,默认0,即不指定最大的晋升大小,一切由运行情况决定,使用 SerialGC、ParNew 时有效
  • -XX:MaxGCPauseMillis=,预期 GC 暂停时间,使用 G1 时可用
  • -XX:G1NewSizePercent,初始年轻代占整个 Java Heap 的大小,默认值为 5%
  • -XX:G1MaxNewSizePercent,最大年轻代占整个 Java Heap 的大小,默认值为 60%
  • -XX:G1HeapRegionSize,设置每个 Region 的大小,单位 MB,需要为 1、2、4、8、16、32 中的某个值,默认是堆内存的 1/2000。如果这个值设置比较大,那么大对象就可以进入 Region 了
  • -XX:+InitiatingHeapOccupancyPercent,G1 内部并行回收循环启动的阈值,默认为 Java Heap的 45%。这个可以理解为老年代使用大于等于 45% 的时候,JVM 会启动垃圾回收。这个值非常重要,它决定了在什么时间启动老年代的并行回收
  • -XX:G1HeapWastePercent,G1停止回收的最小内存大小,默认是堆大小的 5%。GC 会收集所有的 Region 中的对象,但是如果下降到了 5%,就会停下来不再收集了。就是说,不必每次回收就把所有的垃圾都处理完,可以遗留少量的下次处理,这样也降低了 单次消耗的时间
-XX:ConcGCThreads=N、-XX:ParallelGCThreads=N

  ParallelGCThreads指的是在STW阶段,并行执行垃圾收集动作的线程数。默认情况下,当CPU数量小于8时,ParallelGCThreads的值就是CPU的数量,当CPU数量大于8时,ParallelGCThreads的值等于3+5*cpuCount/8。

  ConcGCThreads指的是并发标记阶段用于执行标记的线程数。G1默认启动的并发线程数是ParallelGCThreads/4,而CMS是(ParallelGCThreads+3)/4。

并发是指垃圾收集器和应用程序交替执行,并行是指应用程序停止,同时由多个线程一起执行GC。因此并行回收器不是并发的。因为并行回收器执行时,应用程序完全挂起,不存在交替执行的步骤。

分析诊断
  • -XX:+-HeapDumpOnOutOfMemoryError,当 OutOfMemoryError 产生时自动 dump 堆内存
  • -XX:HeapDumpPath=,与 HeapDumpOnOutOfMemoryError 搭配使用,指定内存溢出时 dump 文件的目录。如果没有指定,默认为启动 Java 程序的工作目录
  • -XX:OnError=

你可能感兴趣的:(JVM碎碎念)