程序员必备:JVM核心知识点总结( 六 )


在配置文件中还有AlwaysPreTouch这个参数 。
-XX:+AlwaysPreTouch其实,通过 Xmx 指定了的堆内存,只有在 JVM 真正使用的时候,才会进行分配 。这个参数,在 JVM 启动的时候,就把它所有的内存在操作系统分配了 。在堆比较大的时候,会加大启动时间,但它能够减少内存动态分配的性能损耗,提高运行时的速度 。
如下图,JVM 的内存,分为堆和堆外内存,其中堆的大小可以通过 Xmx 和 Xms 来配置 。

程序员必备:JVM核心知识点总结

文章插图
 
但我们在配置 ES 的堆内存时,通常把堆的初始化大小,设置成物理内存的一半 。这是因为 ES 是存储类型的服务,我们需要预留一半的内存给文件缓存 ,等下次用到相同的文件时,就不用与磁盘进行频繁的交互 。这一块区域一般叫作 PageCache,占用的空间很大 。
对于计算型节点来说,比如我们普通的 Web 服务,通常会把堆内存设置为物理内存的 2/3,剩下的 1/3 就是给堆外内存使用的 。
我们这张图,对堆外内存进行了非常细致的划分,解释如下:
  • 元空间 参数 -XX:MaxMetaspaceSize 和 -XX:MetaspaceSize,分别指定了元空间的最大内存和初始化内存 。因为元空间默认是没有上限的,所以极端情况下,元空间会一直挤占操作系统剩余内存 。
  • JIT 编译后代码存放 -XX:ReservedCodeCacheSize 。JIT 是 JVM 一个非常重要的特性,CodeCahe 存放的,就是即时编译器所生成的二进制代码 。另外,JNI 的代码也是放在这里的 。
  • 本地内存 本地内存是一些其他 attch 在 JVM 进程上的内存区域的统称 。比如网络连接占用的内存、线程创建占用的内存等 。在高并发应用下,由于连接和线程都比较多,这部分内存累加起来还是比较可观的 。
  • 直接内存 这里要着重提一下直接内存,因为它是本地内存中唯一可以使用参数来限制大小的区域 。使用参数 -XX:MaxDirectMemorySize,即可设定 ByteBuffer 类所申请的内存上限 。
  • JNI 内存 上面谈到 CodeCache 存放的 JNI 代码,JNI 内存就是指的这部分代码所 malloc 的具体内存 。很可惜的是,这部分内存的使用 JVM 是无法控制的,它依赖于具体的 JNI 代码实现 。
日志参数配置下面是 ES 的日志参数配置,由于 Java 8 和 Java 9 的参数配置已经完全不一样了,ES 在这里也分了两份 。
Java8参数设置:
-XX:+PrintGCDetails-XX:+PrintGCDateStamps-XX:+PrintTenuringDistribution-XX:+PrintGCApplicationStoppedTime-Xloggc:logs/gc.log-XX:+UseGCLogFileRotation-XX:NumberOfGCLogFiles=32-XX:GCLogFileSize=64mJava9参数设置:
-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m
下面解释一下这些参数的意义,以 Java 8 为例 。
  • PrintGCDetails 打印详细 GC 日志 。
  • PrintGCDateStamps 打印当前系统时间,更加可读;与之对应的是 PrintGCTimeStamps,打印的是 JVM 启动后的相对时间,可读性较差 。
  • PrintTenuringDistribution 打印对象年龄分布,对调优 MaxTenuringThreshold 参数帮助很大 。
  • PrintGCApplicationStoppedTime 打印 STW 时间
  • 下面几个日志参数是配置了类似于 Logback 的滚动日志,比较简单,不再详细介绍
从 Java 9 开始,JVM 移除了 40 多个 GC 日志相关的参数,具体参见 JEP 158 。所以这部分的日志配置有很大的变化,GC 日志的打印方式,已经完全不一样了,比以前的日志参数规整了许多 。
参数如下所示:
-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=32,filesize=64m
再来看下 ES 在异常情况下的配置参数:
-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=data-XX:ErrorFile=logs/hs_err_pid%p.log
HeapDumpOnOutOfMemoryError、HeapDumpPath、ErrorFile是每个 Java 应用都应该配置的参数 。正常情况下,我们通过 jmap 获取应用程序的堆信息;异常情况下,比如发生了 OOM,通过这三个配置参数,即可在发生OOM的时候,自动 dump 一份堆信息到指定的目录中 。
拿到了这份 dump 信息,我们就可以使用 MAT 等工具详细分析,找到具体的 OOM 原因 。
垃圾回收器配置ES 默认使用 CMS 垃圾回收器,它有以下三行主要的配置 。
-XX:+UseConcMarkSweepGC-XX:CMSInitiatingOccupancyFraction=75-XX:+UseCMSInitiatingOccupancyOnly


推荐阅读