JVM垃圾收集原因、算法

JVM垃圾收集原因、算法

垃圾收集Garbage Collection 简称GC

为什么要垃圾收集和内存分配

当需要派彩各种内存溢出 内存泄漏问题是当垃圾收成为系统达到更高并发量的平静时 我们必须堆这些自动化技术实施必要的监控和调节

栈不需要太关注

程序计数器、虚拟机栈、本地方法栈随线程而生 随线程灭每一个 当线程结束时 内存自然就跟着回收了

而java heap和 方法区这两个区域有很显著的不确定性

一个接口的多个实现类需要内存肯能会不一样 一个方法所执行的不统条件分支所需要的内存也可能不一样只有处于运行期间才能知道程序究竟会创建哪些对象 创建多少个对象 这部分内存的分配和回收是动态的 垃圾收集器所关注的正式这部分内存该如何管理

判断是否还可以存活

一、引用计数算法(Reference Counting)

在对象中添加一个引用计数器 每当一个地方引用他时 计数器值就+1 当引用失效的时候计数器值-1

计数器为零的对象就是不能再被使用的

微软 COM ActionScript FlashPlayer Python 语言

缺点:

1、占用了一些额外的内存空间来进行计数,原理简单判断效率高多数情况下是一个不错的算法

2、Java虚拟机没有选用引用技术算法来管理内存 主要原因是 这个看似简单的算法有很多例外情况要考虑 必须要配合大量额外处理才能保证正确的工作 单纯的引用技术很难解决对象之间相互循环引用的问题

eg:在这里插入图片描述

在JDK1.2之后 Java对引用概念进行了扩充将引用分为强引用 Strongly Re-freence

软引用Soft-reference 弱引用 Weak Reference 虚引用 PHantom Reference 这四种引用强度

二、可达性分析算法

主流语言java C# 内存管理子系统都是通过可达性分析算法判断对象是否存活这和个基本思路就是通过一些GC ROOTs的对象作为其实节点集 从这些节点根据相互搜索

在这里插入图片描述

Java体系中 可以作为GC roots的对象包括

1、虚拟机栈(栈帧中的本地方法表)中引用的对象

2、方法区静态属性引用的对象譬如Java类的引用类型静态变量

3、在方法区中常量引用的对象 比如字符串常量池里的引用

4、在本地方法栈中JNI通常说的Native引用对象

5、java虚拟机内部引用基本数据类型对应的Class 对象一些常驻的异常对象

6、所有被同步锁synchronized 持有的对象

7、反应Java虚拟机内部情况的JMXBean HjVMTI中注册的回调本地代码缓存

除此之外还有个用户所选的垃圾回收器以及当前回收的内存区域不同还有其他对象临时加入

还有分代收集和局部回收在这里插入图片描述

即使是可达性分析算法判定不可达对象也不是非死不可,这时候他们暂时还处于缓刑阶段 要真正宣告一个对象死亡,至少要经历两次标记过程 如果对象在进行可达性分析后没有与GC Roots相连接的引用链 他将会被第一次标记 随后进行一次筛选 筛选的条件是此对象是否有必要执行finalized()方法 加入对象没有覆盖 finalized()方法

回收方法区

垃圾收集行为 事实上也确定有未实现或未能完整实现方法区类型卸载的收集器存在,方法区垃圾收集的性价比比较低 在Java堆中 新生代 堆常规应用进行一次垃圾收集通常可以回收70%至99%的内存空间相比之下 方法会有苛刻判定条件

方法区的垃圾收集主要两部分

废弃的常量和不再使用的类型

*该类所有的实例都已经被回收,也就是Java堆中不存在该类以及其任何派生子类的实例

*加载该类的加载器已经被回收这个条件除非是经过精心设计的可替换类加载器的场景

*该类对应的java.lang.Class对象美欧任何地方被引用 无法在任何地方通过反射访问该类的方法

大量的使用反射、动态代理、CGLib等字节码框架动态生成JSP以及OSGI这类频繁自定义加载器场景中

垃圾回收算法(本文主要是追踪式垃圾收集)

理论基础:分代收集Generational Collection 分代收集 符合大多数程序运行实际情况的经验法则 建立两个分代假说之上 1、弱分代假说:绝大多数对象朝生夕灭 2、强分代假说:熬过越多此垃圾收集对象越难消亡

这两个分代假说共同奠定了多款常用的垃圾收集器:收集器应该将Java堆划分出不同的区域,然后将回收对象依据其年龄分配到不统的区域之中存储

Java堆划分为新生代老年代在这里插入图片描述

垃圾收集算法

标记清除算法 :

最早最基础的垃圾收集算法

算法分为标记和清除两个阶段 首先标记出所有需要回收的对象,标记完成后统一回收掉所有被标记的对象,也可以反过来表机存活的对象。统一回收未被标记的对象标记过程就是第项是一个属于垃圾的判定过程

缺点:执行效率不稳定 如果大部分需要被回收 必须要进行大量的标记清除动作对象的增长而执行效率降低

内存空间碎片化:标记清除之后产生大量不连续的内存碎片空间碎片太多可能导致产生大量不连续的内存碎片

在这里插入图片描述

标记复制算法

标记-复制算法 常被简称为复制算法 为了标记-清除算法面对大量可回收对象执行效率低,

步骤1、可用内存按容量划分为大小相等的两块 没此只使用其中的一块 当一块内存用完了 就将还存活着的对象复制到另一块上面然后再把已使用过的内存哦那关键一次清理掉

步骤2、如果内存中多数对象都是存活的,这种算法将会残生大量的内存间复制的开销但对于多数对象都是可回收的情况,算法需要复制的就是站少量的存活对象

每次都是针对整个半区进行内存回收,分配内存时也就不用考虑有空间碎片的复杂情况只要推动堆顶指针 按顺序分配即可 实现简单 运行高效不过其缺陷也显而易见

在这里插入图片描述

现在的商用Java虚拟机大多都有限采用了这种收集算法区回收新生代

Andrew Appel 针对朝生夕灭特点 提出更优化的搬去复制分代策略现在称之为Appel式回收

HotSpot虚拟机的Serial,ParNew等新生代收集器采用策略来设计新生代的内存布局

​ Appel式回收的具体做法把新生代分成一块较大的Eden空间和两块的Survivor空间 每次分配内存值使用Eden和Survivor。发生垃圾收集时,将Eden和Survivor中任然存活的对象一次性复制到另一块Survivor空间上

HotSpot虚拟机和Eden和Survivor的大小比例时8:1 每次咸亨代中可用内存空间为整个新生代容量的90%(Eden80% Survivor 10%)只有一个新生代 10%会被浪费掉

标记整理算法

块Survivor空间上

HotSpot虚拟机和Eden和Survivor的大小比例时8:1 每次咸亨代中可用内存空间为整个新生代容量的90%(Eden80% Survivor 10%)只有一个新生代 10%会被浪费掉

标记整理算法

针对老年代对象的存亡特征其标记的过程仍与标记清除算啊一样,但时后续不走不是直接对可回收对象进行清理 而是让所有的存活对象都向内存另一个端移动 然后直接清理掉边界意外的内存
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值