JVM性能调优

一、JVM内存划分

  • 年轻代(New):年轻代用来存放JVM刚分配的Java对象
  • 年老代(Tenured):年轻代中经过垃圾回收没有回收掉的对象将被Copy到年老代
  • 永久代(Perm):永久代存放Class、Method元信息,其大小跟项目的规模、类、方法的量有关,一般设置为128M就足够,设置原则是预留30%的空间。

二、垃圾回收执行过程

  • 当年轻代内存满时,会引发一次普通GC,该GC仅回收年轻代。需要强调的时,年轻代满是指Eden代满,Survivor满不会引发GC
  • 当年老代满时会引发Full GC,Full GC将会同时回收年轻代、年老代
  • 当永久代满时也会引发Full GC,会导致Class、Method元信息的卸载

  另一个问题是,何时会抛出OutOfMemoryException,并不是内存被耗空的时候才抛出

  • JVM98%的时间都花费在内存回收
  • 每次回收的内存小于2%

  满足这两个条件将触发OutOfMemoryException,这将会留给系统一个微小的间隙以做一些Down之前的操作,比如手动打印Heap Dump。

三、内存泄漏及解决方法

 1.系统崩溃前的一些现象:

  • 每次垃圾回收的时间越来越长,由之前的10ms延长到50ms左右,FullGC的时间也有之前的0.5s延长到4、5s
  • FullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC
  • 年老代的内存越来越大并且每次FullGC后年老代没有内存被释放

 之后系统会无法响应新的请求,逐渐到达OutOfMemoryError(内存溢出)的临界值。

 2.生成堆的dump文件

 通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动JMX可以通过Java的jmap命令来生成该文件。

 3.分析dump文件

Eclipse专门的静态内存分析工具:Mat

4.分析内存泄漏

 通过Mat我们能清楚地看到,哪些对象被怀疑为内存泄漏,哪些对象占的空间最大及对象的调用关系。

 四、回归问题

   Q:为什么崩溃前垃圾回收的时间越来越长?

   A:根据内存模型和垃圾回收算法,垃圾回收分两部分:内存标记、清除(复制),标记部分只要内存大小固定时间是不变的,变的是复制部分,

因为每次垃圾回收都有一些回收不掉的内存,所以增加了复制量,导致时间延长。所以,垃圾回收的时间也可以作为判断内存泄漏的依据

   Q:为什么Full GC的次数越来越多?

   A:因此内存的积累,逐渐耗尽了年老代的内存,导致新对象分配没有更多的空间,从而导致频繁的垃圾回收

   Q:为什么年老代占用的内存越来越大?

   A:因为年轻代的内存无法被回收,越来越多地被Copy到年老代

原文地址:https://www.cnblogs.com/zhangwangvip/p/13452694.html