GC回收机制

堆、栈、方法区

        简单描述:堆只存放具体对象,new出来的对象会存在于堆中,内存的管理与清理垃圾由JVM的GC来管理和清理。

                        栈:存放基础数据类型、变量名,变量名会指向其针对的堆中对象的地址值。

                        方法区:用于存放整个程序唯一的值,比如静态变量,class信息,方法区中有个常量池,用于存放类中常量

程序员不需要关心内存如何分配,以及如何释放内存,释放内存由JVM来操作。

JVM清理内存的步骤大体分为两个步骤:

                        1.将无用的对象标记出来

                        2.将被标记的对象删除

如何判断什么对象应该被回收

   标记的方法有两种:

        1.引用计数器

                每个对象都会有一个对应的引用计数器,当对象被引用一次计数器将+1,如果没有引用计数器则归零,归零的对象则代表无用了,会被GC回收掉。

                但是此方法会存在内存泄露,举个例子:

                        对象A和B被new出来,此时A和B各被引用一次,计数器各+1。
                        将A和B相互赋值,A和B的引用再+1,但是此时的+1时存在于堆空间中的引用

                        将A和B置空让他们=null

                此时将变量表中的引用切断了,计数器为0,但是对空间的A和B其实计数器还是1,那么不符合回收条件,不予回收。

        2。可达性分析法

                大部分虚拟机使用的时可达性分析法。它有两个概念:GC roots 、可达性

                GC roots:被栈中变量表所引用的对象、被方法区中静态变量或常态变量所引用的对象、被本地方法栈jni所引用的对象

                可达性:可达性对象就是可以和GC roots构成链接的对象

                如果对象有可以到达的GC roots,则代表该对象满足可达性。如果对象无可达的GC roots ,则不满足可达性,会被清除。(简单来说就是,对象是否有被变量表所引用,如果没有引用则被清除,如果变量表中有引用到,则还有用,不会被清除

如何回收清理

        标记了哪些对象可以清理后,接下来要考虑如何高效清理垃圾。

常用的清理方法有:

                1.标记-清理 算法

                2.复制 算法

                3.标记-整理 算法

                4.分代 算法

        1.标记-清理 算法

                最容易实现的算法,也就是直接将标记过的对象进行清除。

                缺点:容易产生大量内存碎片,如果有对象需要分配大量内存的时候,会因为找不到足够的内存空间,所以提前触发新的垃圾回收。

        2.复制 算法

                为了解决(标记-清理)所产生的内存碎片问题,复制算法出现了。

                复制算法会将内存分为两个区域A、B,先将对象放在A区域,当A区域存放满了,将A中存活的对象复制到B中,复制过去使用的内存空间都聚集在一起,所以不会有内存碎片,然后清理A中剩余的对象,如果B满了,做同样的动作往A中复制。

                缺点:浪费的空间太大,一次只能使用一半的空间,这种算法一般只存在理论,一般使用的是它的升级版算法。

        3.标记-整理 算法

                为了解决内存碎片和浪费内存空间的问题,标记-整理出现了。

                实现方法很简单,将要清除的对象标记,然后将未被标记的对象移动到内存空间的一端,然后删除其余的对象。这样既可以解决内存碎片问题,也可以解决浪费内存资源的问题。

                缺点:效率上来说没有复制算法来的快

                        如果移动了对象的内存位置,如果该对象被应用,还要调整引用地址

                        在移动的过程中,需要停止用户程序操作。

            4.分代 算法

                        可以理解成分代算法融合了前面几种,分代算法分为:新生代、老年代。频繁增删的小对象在新生代中处理,长时间存活的大对象在老年代中处理。

                新生代:

                        新生代分为两个区域,Eden区、survivor区,而survivor区又分为from区和to区(这里和复制算法的A、B区很相似),还有一个新概念是对象年龄计数器(每当对象活过一次清理,年龄+1)。

                        1.新产生的对象会进入Eden区,如果Eden区存满了会进行清理,存活下来的

                           对象会进入survivor区的from区,并且年龄+1,然后将标记的对象删除

                        2.Eden区继续处理对象,满了再触发清理,此时将eden区和from区存活的对象都

                           复制到to区,然后将标记的对象删除。

                随后就是反复重复以上动作,survivor区的from和to区就是左右复制(和刚才说的复制算法一样)。

                老年代:

                什么样的对象可以进入老年代:

                        1.大对象,比如很长的字符串、数组,此等需要很长的连续性内存的对象可以直接

                                老年代存放。

                        2.survivor区中存活时间过长的对象可以晋升至老年代。比如年龄大于15岁可以进入

                        3.当survivor区放不下的时候,老年代可以当作新生代的备用库进行存放。

                老年代如何清理对象:

                        由于老年代存放的都是长时间无需清理的数据,所以可以使用标记-整理算法,就算是消耗时间比较长,但是频率低,所以影响不大。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值