Java虚拟机笔记(二)

欢迎扫码关注我 😊 算法

image

判断对象是否存活

1、引用计数算法

​ 给对象中添加一个引用计数器,每当有一个地方引用他时就给计数器值加一;当引用失效时,计数器值就减一;任什么时候刻计数器为0的对象就是不可能再被使用的。数组

​ 缺点:很难解决对象之间互相循环引用的问题。安全

2、可达性分析算法

​ 以“GC Root”对象为起始点,今后节点向下搜索,搜索所走的路径成为引用链,当一个对象和GC Root之间没有任何引用链的时候,则此对象为不可用对象。微信

可达性分析算法判断对象是否能够回收

如上图所示,Object1到Object4与GC Root之间存在引用链,因此Object1到Object4的对象是可达对象,而Object5和Object6没有雨GC Root相关的引用链,因此Object5和Object6是不可达对象,是能够回收的对象。多线程

​ Java中能够被称为GC Root的对象有如下几种:并发

  • 虚拟机栈中引用的对象线程

  • 方法区中类静态属性引用的对象cdn

  • 方法区中常量引用的对象server

  • 本地方法栈中JNI(Native方法)引用的对象对象

3、四种引用类型

  • 强引用:相似于new一个对象的引用,只要强引用存在,垃圾收集器永远不会回收掉被引用的对象。

  • 软引用:描述的是一些还有用但并不是必须的对象,对于软引用关联的对象,在系统将要发生内存溢出以前,会把这些对象列进回收范围之中进行第二次回收,若是此次回收尚未足够的内存就会抛出内存溢出异常。

  • 弱引用:描述非必须对象,被弱引用关联的对象只能生存到下一次垃圾收集发生以前。当垃圾收集器工做时,不管当前内存是否足够,都会回收只被弱引用关联的对象。

  • 虚引用:一个对象是否有虚引用存在,彻底不会对其生存时间构成影响,也没法经过虚引用来取得一个对象实例。为一个对象设置虚引用关联的惟一目的就是当这个对象被收集器收集时会收到一个系统通知。

若是一个对象在可达性分析时没后没有与GC Root相链接的引用链,它将会第一次标记并筛选,筛选条件是该对象是否有必要执行finalize()方法,若是有必要执行finalize()方法,对象只要从新与引用链上的任何一个对象创建关联便可,拿在第二次标记时将他移除“即将回收”集合。任何对象的finalize()方法只会被调用一次,若是对象面临下一次回收,它的finalize()方法不会被再次执行。

垃圾收集算法

1、标记—清除算法

​ 首先标记出全部要回收的对象,在标记完成后统一回收被标记的对象。

​ 缺点:一、效率问题,标记和清除两个过程的效率都不高。 二、空间问题,标记清除会产生大量不连续的内存碎片,空间碎片太多会致使之后程序运行过程当中须要分配较大对象时,没法找到足够的连续内存而不得进行另外一次垃圾收集动做。

2、复制算法

​ 将内存安容量分为大小相等的两块,每次只使用其中一块,当着一块内存用完后,将存活的对象复制到另外一块上面,再把已使用的内存清理掉。

​ 通常虚拟机是将内存分为一块较大的Eden空间和两块较小的Survivor空间。每次使用?Eden和其中一块Survivor,回收时,将Eden和Survivor还存后的对象复制到Survivor空间,再清理掉刚才用到的Survivor和Eden空间。当Survivor内存不足时会用到其余内存(老年代)进行分配担保。

​ 缺点:在对象存活率较高时就要进行较多的复制操做,效率会变低,老年代通常不能直接选用这种作法。

3、标记—整理算法

​ 标记过程与标记—清除算法相同,而后让全部存活的对象都像一端移动,而后直接清理掉端边界之外的内存。适用于老年代整理。

三种垃圾收集算法图片

4、分代收集算法

​ 通常根据对象存活周期将对象划分为几块。Java堆分为新生代和老年代。新生代通常采用复制算法,而老年代对象存活较高,没有额外空间对它进行分配担保,就必须使用标记—清除或标记—整理算法。

垃圾收集器

1、Serial收集器

​ 是虚拟机在client模式下默认的新生代收集器,是单线程收集器,必须停掉其余全部工做线程,知道他收集结束。

2、ParNew收集器

​ 时Serial收集器的多线程版本。是许多运行在server模式下的虚拟机的首选的新生代收集器。除了Serial收集器外,只有它能与CMS收集器配合工做。

3、Parallel Scavenge收集器

​ 并行多线程的新生代收集器。CMS等收集器的特色是尽量缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目的是达到一个可控制吞吐量。吞吐量是指CPU用于运行用户代码的时间与CPU总消耗的时间的比值

4、Serial Old收集器

​ 是Serial收集器的老年代版本,单线程收集器。主要是给client模式下的虚拟机使用。在server模式下:一是能够与Parallel Scavenge收集器配合使用。另外一方面是做为CMS收集器的后备方案。

5、Parallel Old收集器

​ 是Parallel Scavenge收集器的老年代版本,使用多线程和标记—整理算法。

6、CMS收集器

​ 是一种以获取最短回收时间为目标的收集器。基于标记—清除算法实现。运做过程:

  1. 初始标记
  2. 并发标记
  3. 从新标记
  4. 并发清除

其中初始标记和从新标记须要“stop the world”,并发标记和并发清除是和用户线程一块儿进行的。

缺点:一、对CPU资源敏感,由于占用了一部分线程而致使应用程序变慢,总吞吐量会下降。

​ 二、收集器没法处理浮动垃圾。

​ 3.采用标记—清除算法会产生大量空间碎片。

7、G1收集器

​ 面向服务端应用的垃圾收集器。优势以下:

  • 并行并发

  • 分代收集

  • 空间整合

  • 可预测停顿

它将整个Java堆分为多个大小相等的独立区域,保留新生代和老年代概念,但他们不是物理隔离,都是一部分Region的集合。G1跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据容许的手机时间,优先回收价值大的Region。

G1的操做步骤:

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收

内存分配与回收策略

1、对象优先在Eden分配

2、大对象直接进入老年代

​ 须要大量连续的内存空间的Java对象,最典型就是很长的字符串以及数组。

3、长期存活的对象进入老年代

​ 虚拟机给每个对象定义年龄计数器,在Eden代出生并通过一次Minor GC仍存后,并能被Survivor接收,被移到Survivor空间中,年龄加一。在Survivor中每熬过一次GC,年龄就加一。当年龄到必定长度后就进入老年代。

4、动态对象年龄判断

​ 若是在Survivor中的相同年龄全部对象大小的总和大于Survivor空间的一半,年龄大于等于改年龄的对象就会进入老年代。

5、空间分配担保

​ 在Minor GC前虚拟机会先检查老年代最大可用的连续空间是否大于新生代全部对象的总空间,若是条件成立,那么Minor GC能够确保安全。不然虚拟机会查看HandelPromotionFailure设置的值是否容许担保失败,若是是,则在检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,若是大于,尝试进行一次Minor GC。不然进行一次Full GC


欢迎关注公众号:

公众号微信
相关文章
相关标签/搜索