垃圾回收GC经典算法
目录
- 垃圾回收GC(Garbage Collection)
- 1、什么是垃圾
- 2、为什么要有GC
- 经典的GC算法
- 1、基本的一些概念
- 2、标记清除算法(Mark and Sweep)
- 3、复制法(copy)
- 4、引用计数法(Reference Counting)
- 5、分代式垃圾回收法(Generational GC)
- 总结
垃圾回收GC(Garbage Collection)
1、什么是垃圾
c语言中malloc申请完内存后,需要手动回收free。
当忘记回收时就产生了垃圾
2、为什么要有GC
- 经常忘记回收
- 容易出现多次回收的情况
经典的GC算法
1、基本的一些概念
我们将内存视为一张有向图
每个数据块(block)在有向图中都是一个节点
每个指针在有向图中是一条边
根节点:包含指针指向堆但是不位于堆内的数据块称作根节点(例如:寄存器,栈上的位置,全局变量等)
可达节点:从根节点到该节点是有一条可达路径的
不可达节点:也就是垃圾,需要回收
2、标记清除算法(Mark and Sweep)
可以建立在malloc/free包之上
问题一:什么时候开始执行该算法?
空间不足时开始(用malloc分配内存直到空间不足out of space)
问题二:空间不足后该算法执行了什么?
标记(Mark):从根节点开始为每一个可达的节点设一个标记位
清楚(Sweep):扫描所有的节点并且释放那些没有被标记的节点
问题三:如何设标记位?
在每一个数据块(block)的头部使用一个额外的位进行标记
具体诠释:
伪代码:
void GC(){HaltAllProcessing();ObjectCollection Roots=GetRoots();//找到所有的根节点for(int i=0;i<root.Count();i++){Mark(root[i]);//标记}Sweep();//清除
}
包含三个阶段:
- 收集所有的根节点
- 从根开始标记所有可达节点
- 最后清除
第一个阶段:收集所有的根节点
运行时系统需要为GC提供一些方法来收集根节点的列表
例如:.NET维护这些根节点并且向GC提供API来收集这些根节点
第二个阶段:从根开始标记所有可达节点
伪代码:
ptr mark(ptr p){if(!is_ptr(p)) return; //如果p不是指针的话,什么都不做if(markBitSet(p)) return; //如果p已经被标记了的话,直接返回setMarkBit(p); //标记pfor(i=0;i<length(p);i++){ //遍历判断p数据块是否指向其他节点mark(p[i]); }return;
}
关于如何判断p是否是一个指针,还没有搞懂,搞懂再写zzz
第二个阶段:清除
伪代码:
ptr sweep(ptr p,ptr end){ while (p<end){if (markBitSet(p)){clearMarkBit();//如果被标记了,就清除标记位,相当于置空}else if (allocateBitSet(p)){free(p);//如果没有被标记,且分配了空间就释放这一块空间}p+=length(p);//通过加上p的长度来到达下一个block,达到遍历整个heap的效果}
}
优缺点
优点:
不用自己写代码去释放内存,当heap满了的时候,它会自动执行
这种方式可以找到所有应该被释放的内存
缺点:
这种GC算法执行的时候会中断其他的进程,性能上可能会出现一个突然的下降
如上图所示:容易造成内存碎片
3、复制法(copy)
基本思路:使用2个堆
一个堆用在程序运行时
一个堆只在GC时使用
该GC算法执行步骤
- 从根节点开始遍历可达数据
- 从from-space(程序运行时的堆)复制可达数据到to-space(GC时使用的堆)
注意:不可达节点留在了from-space- 交换两个堆(即原来的from-space变为了to-space)
具体诠释:
优缺点
优点:
相较于标记和扫描算法,该算法运行速度更快。因为它只扫描了一次堆。
缺点:
缺点也很明显,只有效使用了堆空间的一半(典型地用空间换取时间)
4、引用计数法(Reference Counting)
基本思路:
跟踪指向每个对象的指针的数量
当引用计数的数量为0时,说明该对象是无法访问的垃圾
具体诠释:
优缺点:
优点:
该算法具有动态的优点,每当有分配或其他堆操作的时候,就执行该算法。
缺点:
无法检测到不可访问的循环列表
计数的成本高:过多的引用计数的增和减
目前的应用情况
在java中没有引用计数
Python还使用引用计数,并提供周期性检测
5、分代式垃圾回收法(Generational GC)
根据经验观察发现:
如果一个对象被访问了很长一段时间,它很可能会维持这样
在大多数的语言中:大多数的对象died young
结论
我们可以通过经常扫描新生代对象,很少扫描老一代对象来节省工作
达尔文的进化论:新生物种总是最容易被淘汰的。
具体诠释:
基本思路
将对象分配给不同的代G0,G1…
G0包含了新一代的对象,最有可能成为垃圾,
G0扫描的频率高于G1
效率得到大幅度提升
总结
- 引用计数是解决显式内存分配问题的常用解决方案。实现赋值时递增和递减操作的代码通常是程序缓慢的原因之一。无论如何,引用计数也不是全面的解决方案,因为循环引用从不会被删除。
- 垃圾回收只会在内存变得紧张时才会运行。当内存尚且宽裕时,程序将全速运行,不会在释放内存上花费任何时间。
- 相对于过去的缓慢的垃圾回收程序,现代的垃圾回收程序要先进得多。分代、复制回收程序在很大程度上克服了早期的标记&清除算法的低效。
- 现代垃圾回收程序进行堆紧缩。堆紧缩将减少程序引用的页的数量,这意味着内存访问命中率将更高,交换将更少。
- 采用垃圾回收的程序不会因为内存泄漏的累积而崩溃。采用GC的程序拥有更长期的稳定性。采用垃圾回收的程序有更少的难以发现的指针错漏。这是因为没有指向已经释放的内存的悬挂指针。因为没有显式的内存管理代码,也就不可能有相应的错漏。
- 采用垃圾回收的程序的开发和调试更快,因为不用开发、调试、测试或维护显式的释放代码。
垃圾回收并非什么仙丹妙药。它有着以下不足:
- 内存回收何时运行是不可预测的,所以程序可能意外暂停。
- 运行内存回收的时间是没有上界的。尽管在实践中它的运行通常很快,但无法保证这一点。
- 除了回收程序以外的所有线程在回收进行时都会停止运行。
- 垃圾回收程序也许会留下一些本该回收的内存。在实践中,这不是什么大问题,因为显式内存回收程序通常会泄露一些内存,这致使它们最终耗尽所有内存,另一个理由就是显式内存回收程序通常会把内存放回自己的内部内存池中而不是把内存交还给操作系统。
- 垃圾回收应该被实现为一个基本的操作系统内核服务。但是因为现实并非如此,就造成了采用垃圾回收的程序被迫带着它们的垃圾回收实现到处跑。尽管这个实现可以被做成一个共享DLL,它也还是程序的一部分。
垃圾回收GC经典算法相关推荐
- java知识点8——垃圾回收原理和算法、通用的分代垃圾回收机制、 JVM调优和Full GC、开发中容易造成内存泄露的操作
垃圾回收原理和算法 内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可 垃圾回 ...
- GC:垃圾回收机制及算法
GC:垃圾回收机制及算法 关键词 算法:标记(清除/复制/整理).分代收集 收集器(Serial[串行].ParNew[并行].Parallel Scavenge[并行].Serial Old[串行] ...
- java jvm垃圾回收算法_深入理解JVM虚拟机2:JVM垃圾回收基本原理和算法
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 喜欢的话麻烦点下Star哈 文章将同步到我的个人博客: www.how ...
- 垃圾回收(GC)浅谈
关于内存 计算机通过两个机制,去实现内存的高效使用. 第一种机制是虚拟内存.硬盘的容量其实是远远大于内存的(RAM),虚拟内存会在内存不足的时候,把不经常访问的内存的数据写到硬盘里.虽然说硬盘容量比较 ...
- jvm - 垃圾回收 gc
2019独角兽企业重金招聘Python工程师标准>>> jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收 ...
- [JVM-3]Java垃圾回收(GC)机制和垃圾收集器选择
哪些内存需要回收? 1.引用计数法 这个算法的实现是,给对象中添加一个引用计数器,每当一个地方引用这个对象时,计数器值+1:当引用失效时,计数器值-1.任何时刻计数值为0的对象就是不可能再被使用的.这 ...
- java垃圾回收理解与算法
垃圾回收机制概述 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理.由于有个垃圾回收机制,Ja ...
- java垃圾回收机制标记_Java的垃圾回收机制-垃圾收集算法(一)
当需要排查各种内存溢出,内存泄漏等问题时,当垃圾收集成为系统达到更高并发的瓶颈时,我们有必要深入GC的原理. image.png 常见垃圾回收算法 在查看垃圾回收具体过程的时候,运行程序加上: -XX ...
- python进阶19垃圾回收GC
原创博客链接:python进阶19垃圾回收GC 垃圾收集三大手段 一.引用计数(计数器) Python垃圾回收主要以引用计数为主,分代回收为辅.引用计数法的原理是每个对象维护一个ob_ref,用来记录 ...
最新文章
- 我挖掘Kafka底层原理!发现了它火爆宇宙的3个真相!
- 庆祝法国队夺冠:用Python放一场烟花秀
- java基础入门-预定义类与自定义类
- app导出excel_Excel教程:Excel_VBA你给我走开!
- 流程表单中js如何清空SheetUser控件数据?
- 标签的属性和样式属性有什么区别
- suse php5,简简单单搭建linux SuSE LAMP环境
- python怎么清理垃圾_Python 中的“垃圾”是怎么回收的?
- 仿B站(一) 目的分析以及创建 WebAPI + Angular7 项目
- 什么是单工、半双工和双工通信?有哪些实际应用的例子
- ubuntu下安装拼音输入法ibus
- 数据机房灾备的重要性
- meshlab简单实践
- Windows 串口驱动下载地址 和 Firefly-RK3399开发板 入手指南
- 转载 测试开发岗--高频知识整理
- 【设计模式】Unity3D 观察者模式
- Anima2D动画简单理解
- Tinyos学习笔记汇总
- Oracle总结【视图、索引、事务、用户权限、批量操作】
- python用matplotlib画球_Python 用matplotlib画以时间日期为x轴的图像
热门文章
- UE4之插件打包提示安装vs2017
- netcore之判断系统
- VMware之虚拟机迁移
- 视频编解码(二):编解码器基础知识
- qchart 怎么点击一下 出一条线_疏通身上一条线,很多难缠病,不知不觉消失了!...
- inline函数_inline内联函数
- 安装mysql查看随机密码命令_deepin安装MySQL没有弹出设置root密码怎么进行修改
- jwt 长度_跟我一起学.NetCore之WebApi接口裸奔有风险(Jwt)
- linux脚本grep,linux shell 脚本之深入浅出的grep的用法
- problem c: 判断素数的函数_python100天 — Day 6 函数和模块的使用