详解JVM内存管理与垃圾回收机制 (上) 下 参数

2.1 关于JVM参数必须知道的小知识

  • JVM参数分为标准参数和非标准参数,所有以-X-XX开头的参数都是非标准参数,标准参数可以通过java -help命令查看,比如:-server就是一个标准参数。
  • 非标准参数中,以-XX开头的都是不稳定的且不推荐在生成环境中使用。但现在的情况已经有所改变,很多-XX开头的参数也已经非常稳定了,但不管什么参数在使用前都应该了解它可能产生的影响。
  • 布尔型参数,-XX:+表示激活选项,-XX:-表示关闭此选项。
  • 部分参数可以使用jinfo工具动态设置,比如:jinfo -flag +PrintGCDetails 12278,能够动态设置的参数很少,所以用处有限,至于哪些参数可以动态设置,可以参考jinfo工具的使用方法。


2.2 GC日志

GC日志是一个非常重要的工具,它准确的记录了每一次GC的执行时间和结果,通过分析GC日志可以帮助我们优化内存设置,也可以帮助改进应用的对象分配方式。如何阅读GC日志不在本文的范畴内,大家可以参考网上相关文章。

下面几个关于GC日志的参数应该加入到应用启动参数列表中:

  • -XX:+PrintGCDetails 开启详细GC日志模式
  • -XX:+PrintGCTimeStamps在每行GC日志头部加上GC发生的时间,这个时间是指相对于JVM的启动时间,单位是秒
  • -XX:+PrintGCDateStamps在GC日志的每一行加上绝对日期和时间,推荐同时使用这两个参数,这样在关联不同来源的GC日志时很有帮助
  • -XX:+PrintHeapAtGC输出GC回收前和回收后的堆信息,使用这个参数可以更好的观察GC对堆空间的影响
  • -Xloggc设置GC日志目录

设置这几个参数后,发生GC时输出的日志就类似于下面的格式 (不同的垃圾收集器格式可能略有差异):

2018-01-07T19:45:08.627+0800: 0.794: [GC (Allocation Failure) [PSYoungGen: 153600K->4564K(179200K)] 153600K->4580K(384000K), 0.0051736 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
......
2018-01-07T19:45:08.627+0800 - GC开始时间
0.794 - GC开始时间相对于JVM启动时间
GC - 用来区分是Minor GC 还是 Full GC,这里是Minor GC
Allocation Failure - GC原因,这里是因为年轻代中没有任何足够空间,也就是分配失败
PSYoungGen - 垃圾收集算法,这里是Parallel Scavenge
153600K->4564K(179200K) - 本次垃圾回收前后年轻代内存使用情况,括号内表示年轻代总大小
153600K->4580K(384000K) - 在本次垃圾回收前后整个堆内存的使用情况,括号内表示总的可用堆内存
0.0051736 secs - GC持续时间
[Times: user=0.01 sys=0.00, real=0.01 secs] - 多个维度衡量GC持续时间

2.3 内存优化

堆空间设置

使用-Xms-Xmx来指定JVM堆空间的初始值和最大值,比如:

java -Xms128m -Xmx2g app

虽然JVM可以在运行时动态的调整堆内存大小,但很多时候我们都直接将-Xms-Xmx设置相等的值,这样可以减少程序运行时进行垃圾回收的次数。

新生代设置

参数-Xmn用于设置新生代大小,设置一个较大的新生代会减少老年代的大小,这个参数堆GC行为影响很大。一般情况下不需要使用这个参数,在分析GC日志后,发现确实是因为新生代设置过小导致频繁的Full GC,可以配置这个参数,一般情况下,新生代设置为堆空间的1/3 - 1/4左右

还可以通过-XX:SurviorRatio设置新生代中eden区和Survivor from/to区空间的比例关系,也可使用-XX:NewRatio设置新生代和老年代的比例。

配置这3个参数的基本策略是:尽可能将对象预留在新生代,减少老年代GC的次数,所以需要更谨慎的对其进行修改,不要太随意。

生成快照文件

我们可能没有办法给最大堆内存设置一个合适的值,因为我们时常面临内存溢出的状况,当然我们可以在内存溢出情况出现后,再监控程序,dump出内存快照来定位,但这种方法的前提条件是内存溢出问题要再次发生。更好方法是通过设置-XX:+HeapDumpOnOutOfMemoryError让JVM在发生内存溢出时自动的生成堆内存快照。有了这个参数,当我们在面对内存溢出异常的时候会节约大量的时间,-XX:HeapDumpPath则可以设置快照的生成路径。堆内存快照文件可能很庞大,要注意存储的磁盘空间

方法区设置

方法区中存放中JVM加载的类信息,如果JVM加载的类过多,就需要合理设置永久大的大小,在JDK1.6和JDK1.7中,可以使用 -XX:PermSize-XX:MaxPermSize来达到这个目的,前者用于设置永久代的初始大小,后者用于设置永久代的最大值。前面我们知道,方法区并不在堆内存中,所以要注意所有JVM参数设置的内存总大小。

JDK1.8中已经使用元空间代替永久代,同样的目的,需要使用-XX:MetaspaceSize-XX:MaxMetaspaceSize来代替。

直接内存

参数-XX:MaxDirectMemorySize用于配置直接内存大小 ,如果不设置,默认值为最大堆空间,即-Xmx当直接内存使用量达到设置的值时,就会触发垃圾回收,如果垃圾回收不能有效释放足够空间,仍然会引起OOM。如果堆外内存发生OOM,请检查此参数是否配置过小。

2.4 小结

这部分主要介绍一些常用的JVM参数,理解这些JVM参数的前提是需要理解JVM的内存结构以及各个内存区域的作用,希望通过这些参数的介绍,能够加深大家对JVM内存结构的理解,也希望在平时的工作中能够注意这些参数的运用。下篇文章将着重介绍常用的垃圾回收算法与垃圾收集器。

 

参考资料

  1. 周志明 著; 深入理解Java虚拟机(第2版); 机械工业出版社,2013
  2. Java8内存模型—永久代(PermGen)和元空间(Metaspace)
  3. java虚拟机:运行时常量池
  4. 最简单例子图解JVM内存分配和回收
  5. JVM的内存区域划分
  6. JVM实用参数(八)GC日志
  7. JVM实用参数(四)内存调优



作者:CHEN川
链接:https://www.jianshu.com/p/f8d71e1e8821
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/ma15732625261/article/details/82085522