JVM垃圾收集之一:什么是垃圾?

本文介绍了Java内存管理中的两种主要算法:引用计数法和可达性分析。引用计数法虽简单高效,但存在循环引用导致的内存泄露问题;可达性分析通过GCRoots确定对象可达性,是现代Java虚拟机的主要内存回收策略。
摘要由CSDN通过智能技术生成

目录

什么是垃圾?

        1.1 引用计数法

        1.2 可达性分析算法

                1.2.1 可达性分析算法

                1.2.2 什么是GC Roots对象呢?


概述

        垃圾收集(Garbage Collection,下文简称GC)诞生于1960年麻省理工学院,应用于古老的Lisp语言,远比java的历史久远, 不要把GC看成是伴随java而生的产物 。

        C和C++对内存的使用和回收都是手动的,程序员手动分配内存,在程序结束时手动回收内存,如此操作增加了程序员开发的工作量,降低了开发效率;同时手动分配内存会容易出现【忘记回收】和【多次回收】的问题。

        Java采用了自动回收内存的策略,编程简单,开发效率高,不会出现手动回收的问题,同样采用自动回收的还有C#,Python,Go等高级编程语言。

什么是垃圾?

        java中什么是垃圾呢?很简单,已经死了的对象就是垃圾。

        如何判断一个对象已经死了呢?

        如上图所示有两种方法可以判断对象是否已死,1,引用计数法;2,可达性分析算法

        1.1 引用计数法

                给对象添加一个引用计数器,当有地方引用该对象时,计数器值会+1;当引用失效时,计数器值会-1;任何时刻计数器值为0的对象,就是死了,就是垃圾了。

                引用计数算法(Reference Counting)原理简单,判定效率高,大多数情况下是一个不错的算法。但引用计数法有很多情况不能保证正确工作。譬如:对象之间相互循环引用,如下图:

1.Dog corgi = new Dog();
2.Cat siam = new Cat();
//  1,2两行代码执行后,main方法栈中会生成两个变量corgi,siam,分别指向堆中new的Dog对象和Cat对象,
//  此时Dog对象和Cat对象的引用计数器值都为1。

3.corgi.cat = siam;
4.siam.dog = corgi;
//  3,4两行代码执行后,Dog对象的cat属性指向Cat对象,Cat对象的dog属性指向Dog对象,
//  此时Dog对象和Cat对象的引用计数器值都为2。

5.corgi = null;
6.siam = null;
//  5,6两行代码执行后,栈中corgi变量和siam变量指向堆中的对象的引用(1)(2)两条引用箭头消失,
//  此时Dog对象和Cat对象的引用计数器值都为1。

                main方法执行完后,main方法的栈帧会被弹栈,main方法创建的对象应该是垃圾的被回收,但是Dog对象和Cat对象的引用计数器值仍然为1,不为0,导致不能被垃圾收集器回收,成为浮动垃圾,造成内存泄露。

                鉴于引用计数算法有一些例外情况导致不能正确完成工作,主流的Java虚拟机里面都没有选用引用计数算法来管理内存,而是用可达性分析算法

        1.2 可达性分析算法
                1.2.1 可达性分析算法

                        通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“引用链”(Reference Chain),如果某个对象到GC Roots间没有任何引用链相连,即从GC Roots到这个对象不可达时,则证明此对象是不可能再被使用的,就是死了,就是垃圾了。

                        如上图所示,object1,2,3,4通过引用链可以回溯到GC Root根对象,即从GC Roots到这个对象可达,所以object1,2,3,4对象都存活;object5,6,7虽然彼此有引用链,但是不能回溯到GC Root根对象,即从GC Roots到这个对象不可达,object5,6,7死了,就是垃圾对象了;

                1.2.2 什么是GC Roots对象呢?

                        熟悉java虚拟运行时内存构造的同学都知道上边这张图,GC Roots对象蕴含在Java虚拟机栈,Java本地方法栈,方法区中。

                        1,Java虚拟机栈

                                虚拟机栈里每个方法栈帧的使用的参数,局部变量,临时变量。

                        2,方法区

                                方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。

                                方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。

                                方法区中基本数据类型,异常类,系统类加载器等对应的Class对象。

                        3,本地方法栈

                                本地方法栈中JNI(即通常所说的Native方法)引用的对象。

                        上述1,2,3提到的都是GC Roots对象,和以上对象有引用链关系的对象,都是根可达对象,也就是存活的对象,堆内存其他的对象都是已死的对象,可以被垃圾收集器回收。

参考:JVM基础篇:垃圾回收-CSDN博客

书籍:深入理解Java虚拟机:JVM高级特性…佳实践(第3版)周志明

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值