JVM调优总结new

 

 堆和栈的平衡

x86的机器上的 进程 最多可以使用 2048mb的内存,

该Java进程剩下的内存由, 方法区,程序计数器,虚拟机栈,本地方法栈 共同使用。

虚拟机栈使用的空间 = 2048- Xmx(最大堆容量)-MaxPermSize (最大方法区容量) - 本地方法栈

我们知道,一个线程对应一个虚拟机栈,

所以总结:那么Heap 越大可以供,程序申请的内存空间越少,就是说虚拟机栈越少(线程数量越少)

堆内存存储了对象,我们称为GC堆,我们增加-Xmx 只是增加了GC堆的大小正真执行程序的内存空间反而小了

 

  1. 对于高并发,创建对象不多的项目,可以降低Xmx的配置, 结合Xms 设定堆范围 -Xms256m -Xmx512 
  2. 对于低并发,创建对象多的项目,(数据处理型的) 可以适当提高,Xmx

 

 -Xmx  指定java程序的最大堆内存

 -Xms  指定初始堆内存, 通常设置成跟最大堆内存一样,减少GC  为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间

 

线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般128K就够用了超过256K考虑优化。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。

 

1.8 优先使用G1

 

分析前查看gc log

接着查看 gc log,打印 gc log 需要在 JVM 启动参数里添加以下参数:

  • -XX:+PrintGCDateStamps:打印 gc 发生的时间戳。
  • -XX:+PrintTenuringDistribution:打印 gc 发生时的分代信息。
  • -XX:+PrintGCApplicationStoppedTime:打印 gc 停顿时长
  • -XX:+PrintGCApplicationConcurrentTime:打印 gc 间隔的服务运行时长
  • -XX:+PrintGCDetails:打印 gc 详情,包括 gc 前/内存等。
  • -Xloggc:../gclogs/gc.log.date:指定 gc log 的路径

 

偏向锁停顿

还有一个问题是 gc log 里有很多 18ms 左右的停顿,有时候连续有十多条,虽然每次停顿时长不长,但连续多次累积的时间也非常可观。

1.8 之后 JVM 对锁进行了优化,添加了偏向锁的概念,避免了很多不必要的加锁操作,但偏向锁一旦遇到锁竞争,取消锁需要进入 safe point,导致 STW。

解决方式很简单,JVM 启动参数里添加 -XX:-UseBiasedLocking 即可。

 

 

JVM常见的调优参数

 -Xmx  指定java程序的最大堆内存

 -Xms  指定初始堆内存, 通常设置成跟最大堆内存一样,减少GC

 -Xmn  设置年轻代大小。整个堆大小=年轻代大小 + 老年代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

 -Xss   指定线程的最大栈空间, 此参数决定了java函数调用的深度, 值越大调用深度越深, 若值太小则容易出栈溢出错误(StackOverflowError)

 -XX:PermSize  指定方法区(永久区)的初始值,默认是物理内存的1/64, 在Java8永久区移除, 代之的是元数据区, 由-XX:MetaspaceSize指定

 -XX:MaxPermSize   指定方法区的最大值, 默认是物理内存的1/4, 在java8中由-XX:MaxMetaspaceSize指定元数据区的大小

 -XX:NewRatio=n  老年代与年轻代的比值,-XX:NewRatio=2, 表示老年代与年轻代的比值为2:1

 -XX:SurvivorRatio=n  Eden区与Survivor(2个)区的大小比值,-XX:SurvivorRatio=8表示Eden区与Survivor区的大小比值是8:1:1,因为Survivor区有两个(from, to)

 

JVM 调优建议

通过设置我们希望达到一些目标:

  • GC的时间足够的小
  • GC的次数足够的少
  • 发生Full GC的周期足够的长

前两个目前是相悖的,要想GC时间小必须要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,我们只能取其平衡。

1)针对JVM堆的设置一般,可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,我们通常把最大、最小设置为相同的值。

2)年轻代和年老代将根据默认的比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者之间的大小,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小

 年轻代和年老代设置多大才算合理?

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC
更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率。

如何选择应该依赖应用程序对象生命周期的分布情况:

如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:

A.本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理。

B.通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间。

5)线程堆栈的设置:每个线程默认会开启1M的堆栈,用于存放栈帧、调用参数、局部变量等,对大多数应用而言这个默认值太了,一般256K就足用。理论上,在内存不变的情况下,减少每个线程的堆栈,可以产生更多的线程,但这实际上还受限于操作系统。

 

 

https://www.cnblogs.com/andy-zhou/p/5327288.html#_caption_25

 JVM -Xmx -Xms 配置误区(越大越好?越大并发量越大?)

posted @ 2019-07-30 22:09  Nausicaa0505  阅读(141)  评论(0编辑  收藏  举报