堆的内存划分

java堆内存划分为新生代,老年代,永久代,在jdk1.8中永久代被元空间取代。新生代又分为三个空间分别为eden,s0,s1区。

  1. 新生代:使用复制清除算法,新生代每次gc都会回收大部分对象,新生代里面分成一份较大的eden空间和两份较小Survivor空间,每次只使用eden和其中一块survivor空间,每次垃圾回收的时候把存活对象复制到未使用的survivor空间中,然后清空eden空间和刚刚使用的survivor空间。eden空间和survivor空间比例为8:1:1,内存不足时发生Minor GC.
  2. 老年代(Old Memory):采用标记整理算法,老年代每次gc都只会回收少量对象。利用可达性遍历内存,把存活对象和垃圾对象进行标记,然后把存活对象全部堆在一起,清空边界以外内存。
  3. 永久代(Perm):用来存储类的元数据,也就是方法区。在jdk1.8中Perm被替换成元空间(MetaSpace),元空间存放在本地内存中。

GC垃圾回收

java垃圾回收机制主要是回收堆和方法区的内存,这块区域的数据是被线程所共享的,而pc寄存器,java虚拟机栈,本地方法栈都是线程独有的,随着线程而产生,随着线程销毁被灭亡。

  1. 可达性分析:通过GC Roots对象作为起点进行搜索,如果在GC Roots和对象之间没有可达路径,则称为对象是不可达的,不可达对象不一定会成为可回收对象。进入DEAD状态的线程还可以恢复,GC不会回收它的内存。把一些对象当做Root对象,JVM认为是不可回收的,并且Root对象引用的对象也是不可回收的。
  2. 什么是root对象:虚拟机栈中引用的对象,方法区中静态属性引用的对象,方法区中常量引用的对象,本地方法栈中Native方法引用的对象。
  3. 对象被回收要经历的两个阶段:
            第一阶段可达性分析,分析该对象是否可达。
            第二阶段当对象没有重写finalize()方法或者finalize()方法已经被调用过,虚拟机认为该对象不可以被救活,因此回收该对象。

虚拟机频繁full GC

full gc清理整个堆空间,包括年轻代和元空间

  • 首先我们用命令查看触发gc的原因是什么jstat -gccause 进程编号
  • 查看代码是否有System.gc()
  • 内存检查heap inspection ,执行jmap  命令
  • 如果是gc locker, 可能是程序依赖的JNI库的原因

垃圾回收算法

  1. Mark-Sweep(标记-清除算法):标记清除算法分为两个阶段,标记阶段和清除阶段。标记阶段是标记出所有需要回收的对象,回收阶段是回收所有被标记的对象的空间。容易产生内存碎片。
  2. Copying(复制清除算法):将可用的内存划分为大小相等的两块,每次只使用其中一块,当前进行垃圾回收的时候,把存活的对象全部复制到另一块中,然后把已使用的内存空间一次清空掉。不容易产生内存碎片,可用内存空间少,存活对象多的话,效率比较低。
  3. Mark-Compact(标记-整理算法):先标记存活对象,然后把存活对象向一边移动,然后清理掉边界以外的内存。不容易产生碎片,内存利用率高,存活对象多并且分散的时候,移动次数多,效率低。
  4. 分代收集算法:新生代每次垃圾回收都要回收大部分对象,所有新生代采用复制算法,新生代里面分成一份较大的eden空间和两份较小的survivor空间,每次只使用Eden和其中一块Survivor空间,然后垃圾回收的时候,把存活对象放到未使用的survivor空间,然后清空eden空间和刚使用的survivor空间。

垃圾回收类型

  1. Minor GC:从年轻代回收内存。
  2. Major GC: 清理整个老年代,当eden区内存不足时触发。
  3. Full GC: 清理整个堆空间,包括年轻代和老年代,当老年代内存不足时触发。

jvm优化

  1. 一般来说当Survior区不够大或者占用量达到50%,就会把一些对象放到老年区。通过设置合理的eden区,survior区及使用率,可以将年轻对象保存在年轻代,从而避免full GC, 使用-Xmn设置年轻代的大小。
  2. 对于占用内存比较大的对象,一般会选择在老年代分配内存。如果在年轻代给对象分配内存,内存不够了,就要在eden区移动大量对象到老年代,然后这些移动的对象可能很快消亡,英雌导致full GC。XX:PetenureSizeThreshold=1000000B,标明对象大小超过1M,将在老年代分配内存。
  3. 一般情况下年轻对象存放在eden区,当一次gc后,对象还存活的话,放在survior区。此后每次gc年龄加一,当对象的年龄到达指定的阈值,就会被存放到老年区中,这个阈值可以通过-XX:MaxTenuringThreshold设置。
  4. 设置最小堆和最大堆,-Xmx和-Xms稳定的堆大小对垃圾回收是有利的。设置-Xmx和-Xms的值一样,可以减少gc次数。虽然减少了gc次数但是增加了gc的时间。                                                                                                                                    -XX:MinHeapFreeRatio参数用于设置堆空间的最小空闲比率,默认40,当堆空间空闲内存比率少于40,jvm会扩展堆。        -XX:MaxHeadFreeRatio参数用于设置堆空间的最大空闲比率,默认70,当堆空间空闲内存比率大于70,jvm会压缩堆。
  5. 、通过增加吞吐量提高系统性能,可以通过设置并行垃圾回收器。                                                                                              -XX:+UseParallelGC: 年轻代使用并行垃圾回收收集器。                                                                                                          -XX:+UseParallelOldGC: 设置老年代使用并行垃圾回收收集器。
  6. 使用大的内存分页。-XX:+LargePageSizeInBytes设置内存页的大小。
  7. 使用非占用的垃圾收集器。-XX:+UseConcMarkSweepGC老年代使用CMS收集器降低停顿。
  8. -XXSurvivorRatio=3,表示年轻代中的分配比率survivor:eden= 2:3
  9. jvm性能调优工具
      jps:输出jvm中运行的进程状态信息。jconsole
      jstack: 查看java进程内存线程的堆栈信息。
      jmap: 用于生成堆转存快照。
      jhat: 用于分析jmap生成的快照。Ecplise Memory Analyzer替代
      jstat: jvm统计监测工具。
      VisualVM: 故障处理工具。