目录
垃圾回收
Java和C++语言的区别,就在于垃圾收集技术和内存动态分配,C++语言没有垃圾收集技术,需要程序员手动收集.
垃圾收集,不是Java语言的伴生产物.早在1960年,第一门开始使用内存动态分配和垃圾收集技术的Lisp语言诞生.
垃圾收集机制是Java的招牌能力,极大地提高了开发效率,如今,垃圾收集几乎称为现代语言的标配,即使经过如此长时间的发展,Java的垃圾收集机制仍然不断的演进中,不同大小的设备,不同特征的应用场景,对垃圾收集提出来新的挑战.
垃圾回收概述
什么是垃圾
垃圾是指在运行程序中没有任何引用指向的对象,这个对象就是需要被回收的垃圾.如果不及时对内存中的垃圾进行清理,这些对象所占的内存空间 一直保留到应用程序结束,被保留的空间无法被其他对象使用,还有可能导致内存溢出.
为什么需要GC
对于高级语言来说,一个基本认知是如果不进行垃圾回收,内存迟早都会被消耗完,因为不断地分配内存空间而不进行回收,就像不停地生产生活垃圾而从来不打扫一样.
处理释放没用的对象,垃圾回收也可以清除内存里的记录碎片.碎片整理将所占用的堆内存移到堆的一端,以便JVM整理出的内存分配给新的对象.
随着应用程序所应付的业务越来越庞大,复杂,用户越来越多,没有GC就不能保证应用程序的正常进行.
早期垃圾回收
在早期的C/C++时代,垃圾回收基本上是手工进行的.开发人员可以使用new关键字进行内存申请,并使用delete关键字进行内存释放.这种方式频繁的申请和释放内存,带来了内存的管理负担,也有可能因为程序员的编码问题导致有些垃圾没有被回收,就会产生内存泄漏.
Java垃圾回收机制
自动内存管理
无需开发人员手动参与内存的分配与回收,这样降低内存泄漏和内存溢出的风险.将程序员从繁重的内存管理中释放出来,可以更专心地专注于业务开发.
存在问题
对于Java开发人员来说,自动内存管理就像是一个黑匣子,如果过度依赖"自动",严重的就会弱化Java开发人员在程序出现内存溢出时的定位问题和解决问题的能力.
所以,了解JVM的自动内存分配回收原理就显得非常重要,只有真正了解JVM是如何管理内存的,程序员才能在遇见OutofMemoryError时,快速地根据错误异常日志定位问题和解决问题.
当需要排查各种内存溢出,内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们必须对这些"自动化"的技术实施必要的监控和调节.
GC的作用域.
GC作用于方法区和堆.
垃圾收集器可以对新生代回收,也可以对老年代回收,甚至全栈和方法区的回收,其中,Java堆时垃圾收集器的工作重点.
从次数上讲:
频繁收集Young区.
较少收集Old区.
基本不收集元空间(方法区).
垃圾回收相关算法
垃圾标记阶段算法
标记阶段的目的
垃圾标记阶段:主要是为了判断对象是否存活.
首先需要区分出堆内存中那些对象是存活对象,那些对象已经是死亡的对象,只有被标记为死亡的对象,GC才会在执行垃圾回收时,释放掉其所占用的内存空间,这个过程我们称为垃圾标记阶段
标记死亡对象的依据:当一个对象不再被任何的存活对象继续引用时,就可以标记死亡.
判断对象存活的方式:引用计数算法和可达性分析算法
1.引用计数算法:
对每一个对象保存一个整型的引用计数器属性,用于记录对象被引用的情况.
对于一个对象A,只要有任何一个对象引用了它,就将它的引用计数器加1.当引用失效时,引用计数器就减1.当对象A的引用计数器的值为0,即表示对象A不可能在碑额使用,可进行回收.
优点
实现简单,垃圾对象便于辨识,判定率高,回收没有延迟性.
缺点
1.他需要单独的字段存储计数器,这样的做法增加了存储空间的开销.
2.每次赋值都需要更新计算器,伴随着加法和减法操作,这增加了时间开销.
3.引用计数器有一个严重的问题,即无法处理循环引用的情况,导致Java的垃圾回收器中没有使用这类算法.
可达性分析算法
也称根搜索算法,追踪性垃圾收集.
相对于计数算法而言,不仅同样具备实现简单和执行高效等特点,更重要的是该算法可以有效地解决在引用计数算法中循环引用的问题,防止内存泄漏的发生.
可达性分析实现思路
所谓"GCRoots"根集合就是一组必须活跃的引用.
1.可达性分析算法是以根对象(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达.
2.使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain).
3.如果目标对象没有任何引用链相连,则是不可达,就意味着该对象已经死亡,可以标记为垃圾对象.
4.在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象.
GC Roots可以是哪些元素?
1.虚拟机栈中引用