JVM的垃圾回收

垃圾回收主要发生在堆上,而堆又分为 年轻代、老年代、永久代三部分,-Xmx表示堆的最大大小,-Xms表示堆的初始大小

新生代

年轻代主要有三个区域:Eden区、survivorFrom、survivorTo区,比例为8:1:1,通常会保证有一个survivor区是空着的,因为JVM每次只会分配Eden和一块survivor区为对象服务,另一块作为备用,对象首先默认在Eden区上分配空间,survivorFrom和survivorTo会相互转化,上一次的From变成这一次的To,因为采用复制算法,哪个区存放存活对象就以哪个区作为From;大对象直接分配到老年代
设置大小:

  • -Xmn 设置年轻代大小,在整个对大小确定的情况下增大年轻代的大小会减小老年代的大小
  • -XX:NewSize = 1024m 设置年轻代的初始值大小
  • -XX:MaxNewSize = 1024m 设置年轻代的最大值

MinorGC过程:
当Eden区满了的时候会触发一次MinorGC,采用复制算法,将MinorGC后Eden区和Survivor区中还存活的对象复制到另一块空闲的survivor块上,也就是survivorTo,并将survivor区中存活的对象年龄加1,年龄到达一定大小就进入老年区,默认15,如果survivorTo也放不下的对象则直接进入老年代;MinorGC之后Eden区和一块surivor区会被清空

老年代

老年代主要存放的对象都是声明周期比较长的对象,很多都是从survivor区熬过来的对象,但是大对象直接进入老年代(需要很多连续空间存储的),例如大数组

引发的条件是当老年代剩余内存无法装载新生代存活的对象和大对象的时候触发

回收机制:FullGC/MajorGC
FullGC:采用的标记-清除算法,FullGC不像MinorGC那么频繁,并且消耗的时间比Minor-GC要长很多,因为要遍历标记整个老年代存活的对象,然后再清除,并且会产生内存碎片; 针对的是整个堆,包括新生代、老年代、永久代

永久代

指永久的内存存放区域,主要存放class文件和Meta(元数据),比如类的层级信息,类的方法数据和方法信息,运行时常量池,已确定的符号引用h和虚方法表;class在被加载的时候被放入永久代,和存放的实例,GC不会在主程序运行期间对永久代进行垃圾回收,这导致永久代随着类加载得class增多而胀满,触发OOM异常;Java8已移除永久代,常量池也单独拉出来了,采用元数据区替代
大小设置:

  • -XX:PermSize = 1024m,设置永久代的初始值
  • -XX:MaxPermSize = 1024m,设置永久代的最大值

永久代的垃圾回收:
垃圾回收不会发生在永久代,但是如果永久代满了或者超过了临界值,就会触发垃圾回收(Full GC),这也就是为什么说合理设置永久代大小能有效避免FullGC

条件:

  1. 该类的实例全部都被回收
  2. 加载该类的类加载器已经被回收
  3. 该类不能通过反射访问到其方法,而且该类的Java.lang.class没有被引用

元数据区

元数据区是在Java8开始设计出来代替永久代的,Java8移除了永久代,但是元数据仍然还存在,元数据区不是在堆空间内,而是在一个和堆不相连的一个本地内存区域,这块区域就被称为元数据区

因为对永久代进行调优很困难的。永久代中的元数据可能会随着每一次FullGC发生而进行移动。并且永久代设置空间也难以确定,因为我们无法确定类的总数,常量池的大小和方法数量

Stop the World现象 STW

stop the world 暂停全世界,简称STW;实际意思是在执行垃圾回收的时候,挂起当前程序其他所有的进程,垃圾回收进程除外;Java中一种全局暂停现象,全局停顿,Nati-ve方法可以继续运行,但是无法与JVM交互。

发生的原因
因为要执行标记,记录哪些对象还活着,所以需要暂停所有用户线程,不管是MinorGC还是FullGC,都会触发

可达性分析算法

通过可达性分析算法来判断哪些对象是无效需要回收的哪些对象是存活的

1.引用计数算法
为每一个创建的对象添加一个引用计数器,用来存储该对象被引用的数量,当引用数量达到0时,则该对象就是不可达的,变成GC的回收对象;这种方式的缺点是只会回收引用数量为0的对象,但是当两个对象互相引用的时候也会被认定是不可回收的
2.可达性分析算法
可达性分析算法时创建一些GCROOT,当一个对象没有跟任何一个GCROOT有引用链时人为该对象是不可用的,常用几种GCROOT对象:

  • 虚拟机栈(栈帧)中的引用对象
  • 方法区中静态属性的引用对象
  • 方法区中常量的引用对象
  • 本地方法栈(JNI)中引用的对象

特点:都是不易被回收的对象

垃圾收集器

1.Serial收集器
单线程收集器,收集时会暂停所有工作线程(我们将这件事情称之为Stop The World,下称STW),使用复制收集算法,虚拟机运行在Client模式时的默认新生代收集器。

2.ParNew收集器
ParNew 收集器就是Serial的多线程版本,除了使用多条收集线程外,其余行为包括算法、STW、对象分配规则、回收策略等都与Serial收集器一摸一样。对 应的这种收集器是虚拟机运行在Server模式的默认新生代收集器,在单CPU的环境中,ParNew收集器并不会比Serial收集器有更好的效果。

3.Parallel Scavenge收集器
Parallel Scavenge收集器(下称PS收集器)也是一个多线程收集器,也是使用复制算法,但它的对象分配规则与回收策略都与ParNew收集器有所不同,它是 以吞吐量最大化(即GC时间占总运行时间最小)为目标的收集器实现,它允许较长时间的STW换取总吞吐量最大化。

4.Serial Old收集器
Serial Old是单线程收集器,使用标记-整理算法,是老年代的收集器,上面三种都是使用在新生代收集器。

5.Parallel Old收集器
老年代版本吞吐量优先收集器,使用多线程和标记-整理算法,JVM 1.6提供,在此之前,新生代使用了PS收集器的话,老年代除Serial Old外别无选择,因为PS无法与CMS收集器配合工作。

6.CMS(Concurrent Mark Sweep)收集器
CMS 是一种以最短停顿时间为目标的收集器,使用CMS并不能达到GC效率最高(总体GC时间最小),但它能尽可能降低GC时服务的停顿时间,这一点对于实时或 者高交互性应用(譬如证券交易)来说至关重要,这类应用对于长时间STW一般是不可容忍的。CMS收集器使用的是标记-清除算法,也就是说它在运行期间会 产生空间碎片,所以虚拟机提供了参数开启CMS收集结束后再进行一次内存压缩。

你可能感兴趣的:(Java虚拟机)