精华内容
下载资源
问答
  • 引用计数法中引入了一个概念,那就是“计数器”。计数器表示的是对象的人气指数, 也就是有多少程序引用了这个对象(被引用数)。计数器是无符号的整数,用于计数器的位数根据算法和实现而有所不同。 被引用的对象...

    1. 引用计数算法

    引用计数法中引入了一个概念,那就是“计数器”。计数器表示的是对象的人气指数,
    也就是有多少程序引用了这个对象(被引用数)。计数器是无符号的整数,用于计数器的位数根据算法和实现而有所不同。
    在这里插入图片描述

    被引用的对象不仅自己计数器要加1,其自己包含的引用的对象的计数器也要加1。

    2.延迟引用计数法

    引用计数法的缺点就是计数器值的增减处理繁重。
    这里就引入了延迟引用计数法,延迟就是先不计数,等时机到了再计数。
    引入一个 ZCT(Zero Count Table)表,来引用那些引用为0的对象。
    被ZCT引用的对象可能不是垃圾。
    当ZCT满时就遍历ZCT引用的对象,开始计算每一个对象被引用的值,计算完后回收那些引用依然为0的对象,剩下的就是有用的对象,再把它们的引用值清零。

    3.Sticky引用计数法

    该方法主要是觉得计数器的值用int类型有点浪费,推荐使用位数少的的数据类型来存储。书上是这样说的:

    计数器需要 1 个字(32 位机器就是 32 位)的空间。但是这样会大量消耗内存空间。
    对此我们有个方法,那就是用来减少计数器位宽的“Sticky 引用计数法”。举个例子,我们假设用于计数器的位数为 5 位,那么这种计数器最多只能数到 2 的 5 次方减 1,也就是 31个引用数。如果此对象被大于 31 个对象引用,那么计数器就会溢出。这跟车辆速度计的指针爆表是一个状况。
    针对计数器溢出(也就是爆表的对象),需要暂停对计数器的管理。对付这种对象,我们主要有两种方法。

    两种方法是:

    1. 什么都不做
      在快要溢出时,不再增加引用值,避免溢出。因为这样的概率太小,绝大多数对象的引用值不会超过1。
    2. 采用标记-清除法辅助。。。
    展开全文
  • 引用计数法

    千次阅读 2016-12-17 18:55:48
    引用计数法是在mutator(应用程序)的启动过程中通过增减计数器的值来进行内存管理 涉及到new_obj和update_ptr函数 //在mutator生成新的对象的时候会调用new_obj函数 new obj ( size ){ obj = pickup_...

    引用计数法是在mutator(应用程序)的启动过程中通过增减计数器的值来进行内存管理

    涉及到new_obj和update_ptr函数

      
    1. //在mutator生成新的对象的时候会调用new_obj函数
    2. new obj(size){
    3.       obj = pickup_chunk(size,$free_list)
    4.       if(obj == NULL)
    5.          allocation_fail()   //pickup_chunk返回NULL的时候,分配就失败了,也就是没有大小合适的分块了
    6.       else
    7.          obj.ref_count = 1 //ref_count是obj的计数器
    8.      return obj
    9. }

      
    1. update_ptr(ptr,obj){
    2. inc_ref_cnt(obj) //对指针新引用的对象obj的计数器进行增量操作
    3. dec_ref_cnt(*ptr) //对ptr之前引用的对象obj计数器进行减量操作
    4. *ptr = obj
    5. }

    为什么先执行inc_ref_cnt(obj)的操作,在进行dec的操作呢 ?这是为了处理*ptr和obj是统一对象的情况,如果先执行dec操作的话,*ptr的值的值就可能变为0而被回收,再执行inc时对象就已经不存在了,会引发重大的bug


    优点:

    1)可即刻回收垃圾,每个对象都知道自己的被引用数ref_count,当ref_count为0时,对象就会把自己作为空闲空间连接到空闲链表,也就是,在对象变成垃圾的同时就会被回收,而其它的GC算法只有当分块用尽GC开始执行时,才会知道哪个是垃圾,也就是GC之前会有一部分内存被垃圾占用

    2)最大暂停时间短,每次通过指向mutator生成垃圾时,这部分垃圾都会被回收,大幅削减了mutator的最大暂停时间

    3)没必要沿指针查找,当我们需要减少沿指针查找的次数是,它就派上用场了

    eg:在分布式环境中,如果要沿各个计算节点之间的指针进行查找,成本就会增大,所以要极力减少沿指针查找的次数


    缺点 :

    1)计数器的值增减处理繁重每次指针更新时,计数器的值会被更新,所以在频繁更新指针的mutator中,值的增减处理会变得繁重

    2)计数器要占很多位,假如32位的机器,就有可能2的32次方个对象同时引用一个对象,所以必须确保各对象的计数器有32位大小,也就是对于所有的对象,必须留有32位的空间,使内存使用大大降低

    3)实现复杂,算法本身简单,但实现复杂,比方说,需要把以往写成*ptr = obj 的地方都要重新写成 update_ptr(ptr,obj)因为调用update_ptr的地方很多,重写过程极易出错

    4)循环引用无法回收,就是两个对象相互引用的情况 比如两个对象是同一个类的实例,属性相互赋值


    ### 延迟引用计数法,针对引用计数法的缺点1提出的改进方法

    缺点1导致的原因之一是从根的引用变化频繁,因此把根引用的变化不反应在计数器上,这样频繁重写堆中的变量指针时,对象的指针值也不会有变化,但因为引用没有反应到计数器,会导致有的对象仍在活动却被当成垃圾回收掉,于是,采用ZCT(Zero Count Table),它是一个表,会记录下在dec_ref_count的作用下变为0的对象,暂时保留,修正dec_ref_count函数,适应延迟引用计数法:

      
    1. dec_ref_count(obj){
    2. obj.ref_count--
    3. if(obj.ref_count == 0) //若zct爆满,先用scan_zct减少$zct中的对象
    4. if(is_null($znt) == true)
    5. scan_zct()
    6. push($zct,obj) //当obj的引用计数为0时添加到zct
    7. }

    修正new_obj函数

      
    1. new_obj(size){
    2. obj = pickup_chunk(size,$free_list)
    3. if(obj == NULL) //若第一次分配失败,意味着空闲链表没有合适的块,
    4. scan_zct() //搜索一遍zct
    5. obj = pickup_chunk(size,$free_list) //再次分配
    6. if(obj == NULL) //依然不行
    7. allocation_fail() //就分配失败了
    8. obj.ref_cnt = 1
    9. return obj
    10. }

    来看下scan_zct函数

      
    1. scan_zct(){
    2. for(r : $roots)
    3. (*r).ref_count++ //把所有通过根直接引用的对象的计数器都进行增量,才把根引用反映到计数器上
    4. for(obj:$zct) //检查与zct相连的对象,若ref_cnt=0,对子对象的计数器减量,并将其回收
    5. if(obj.ref_cnt == 0)
    6. remove($zct,obj)
    7. delete(obj)
    8. for(r : $roots)
    9. (*r).ref_cnt--
    10. }

    优点:延迟了根引用的计数,将垃圾一并回收,通过延迟,减少了根引用频繁变化导致计数器增减带来的额外负担

    缺点:垃圾不能马上回收,失去了引用计数的一大优点:可即刻回收垃圾

    2)scan_cnt使最大暂停时间延长,执行scan_cnt的时间与zct的大小成正比,zct大,妨碍mutator的时间就长,若缩减zct,又使得调用scan_cnt的频率增加,压低吞吐量,很显然本末倒置了


    ### sticky引用计数法:

    计数器占一个字的空间或大大的浪费内存,可以减少计数器的位宽,假设为5位,也就是最多引用32-1次,超过31个对象引用计数器就会溢出,但是,引用对象超过31次的对象肯定是活跃对象,不操作,也不会有大的问题(对溢出不处理)

    使用GC标记-清除算法管理:

    标记阶段:把根直接引用的对象堆到标记栈里,按顺序从标记栈取出对象,对计数器进行增量操作,不过,必须把各对象只标记一次

    清除阶段,会搜索整个堆,回收计数器为0的对象

    与之前的标记清除算法不同:

    1)一开始就把所有对象的计数器的值设置为0

    2)不标记对象,而是对对象的计数器进行增减操作

    3)为了对计数器增量操作,对活动对象多次搜索

    所以,要是把sticky法和GC标记-清除法一起使用,在计数器溢出后程序还是能回收,还可以回收循环垃圾

    但是,在标记之前必须重置所有的对象和计数器,且由于查找对象时需要多次查找,耗时更多,吞吐量会降低



    ### 1位引用计数法

    是sticky引用计数法的极端情况,计数器只有1位

    它称为标签flag更合适,引用对象为1时,标签为unique,大于1时,为multiple

    优点:最不容易出现高速缓存缺失,节省内存消耗

    缺点:计数器溢出


    


    展开全文
  • GC-引用计数法

    千次阅读 2019-04-08 21:16:19
    GC-引用计数法 GC:释放怎么都无法被引用的对象的机制。 引用计数法在对象的元数据区,加入了计数器,用于表示当前对象被引用了多少次。 引用计数法与其他GC算法相比,在于GC的的调用时机:GC标记-清除算法是在没有...

    GC-引用计数法

    GC:释放怎么都无法被引用的对象的机制。

    引用计数法在对象的元数据区,加入了计数器,用于表示当前对象被引用了多少次。
    在这里插入图片描述
    引用计数法与其他GC算法相比,在于GC的的调用时机:GC标记-清除算法是在没有可用分块时,会调用GC函数,进行垃圾处理回收,即是一种无侵入式的GC,这样就造成,最大暂停时间较大,此外,标记-清除算法即是产生了垃圾,也不会将其马上回收,只会在没有分块的时候,将垃圾一并回收;GC引用计数法是一种侵入式算法,其最大暂停时间表现较好,比较均匀,内存管理和mutator同时运行是引用计数法的一大特征。

    在引用计数法中,只有两种,连接到空闲链表的对表,其余都是活动对象。引用计数法中,对象的状态监控是实时的。

    GC-引用计数法的主要内容:

    new_obj(size){//创建对象,分配内存块
        obj=pickup_chunk(size,$free_list)
        if(obj==NULL)
            allocation_fail()
        else
            obj.ref_cnt=1
            return obj
    }
    update_ptr(){ //mutator,引用改变
        inc_ref_cnt(obj)//计数增量
        dec_ref_cnt(*ptr)//计数减量
        *ptr=obj
    }
    //先增量,再减量,主要原因是解决obj和ptr指向同一对象的问题,若先减量,则该对象
    //可能已经成为垃圾,从而造成bug
    inc_ref_cnt(obj){
        obj.ref_cnt++
    }
    dec_ref_cnt(obj){
        obj.ref_cnt--
        if(obj.ref_cnt==0)//没有引用了,即是垃圾了,遍历子对象,进行减量操作
            for(child:children(obj))
                dec_ref_cnt(*child)
            reclaim(obj) //回收
    }
    

    优点:可即刻回收垃圾,当对象计数为0时,会立刻回收;最大暂停时间短,mutator更新指针时才会执行垃圾回收,是一种侵入式,可有效消减最大暂停时间,即将该时间分散到了指针更新时;没有必要沿指针查找,不会像标记-清除算法一样从跟开始遍历。

    在分布式环境中,如果要沿各个计算节点之间的指针进行查找,成本就会增加,就需要极力控制沿指针查找的次数,所以有一种做法是,在各个计算节点内回收垃圾使用GC垃圾-清除算法,在考虑到节点间的引用关系时则采用引用计数法。

    缺点:计数器值的增减处理繁重,只要更新指针,就会进行计数器更新,所以值的增减处理会变得繁重;计数器需要占用很多位,32位机器,可能要让2的32次方个对象同时引用一个对象,考虑这种情况,就需要32位大小,这会使内存空间的使用效率降低;实现繁琐复杂,因为该算法是侵入式的,即需要把*ptr=obj全部更换成update_ptr(ptr,obj);循环引用无法回收,每个对象都有引用计数,就无法回收,但其本身已经是垃圾了。

    class Person{
        string name
        person laver
    }
    A=new Person("A")
    B=new Person("B")
    A.lover=B //循环引用
    B.lover=A
    A=NULL //对于根指针,没有对象引用,已经是垃圾了
    B=NULL
    

    针对GC-引用计数法的一些缺点,进行相关改进:延时引用计数法可解决计数器增减繁重的问题;Sticky引用计数法,可一降低计数器的宽度,提高空间利用率;1位引用计数法,是一种特殊的Sticky引用计数法,使用指针的的后两位作为计数器;部分标记-清除算法,可解决循环引用问题。

    延迟引用计数法:对引用计数延迟操作

    指针引用对象变化,不会立即更新到,这将引用变化更新推迟,推迟到空闲链表中没有满足的分块,同一进行扫描更新。具体体现在将upate_ptr( p t r , o b j ) 改 为 ∗ ptr,obj)改为* ptr,obj)ptr=obj,也就是计数更新只在创建对象时。
    延迟引用计数法,引入一个ZCT(Zero Count Table)表,会事先记录下计数器值在dec_ref_cnt()函数的作用下变为0的对象。之后会扫描该表,更新计数,更新方法同标记-引用算法,从根开始递归扫描。
    在这里插入图片描述

    计数器值为0的对象不一定都是垃圾?因为该改进算法,只在对象生成是计数器+1,之后的引用,并没有更新,所以为0,不一定是垃圾,记录到zct表中,后续遍历确认。

    dec_rec_cnt(obj){
        obj.ref_cnt-- 
        if(obj.ref_cnt==0)//表中记录可能是垃圾的对象
            if(is_full($zct)==TRUE)
                scan_zct()//表满时,进行垃圾扫描和回收
            push($zct,obj)
    }
    new_obj(size){
        obj=pickup_chunk(size,$free_list)//没有满足的分块
        if(obj==NULL)
            scan_zct()//扫描zct表,清理垃圾
            obj=pickup_chunk(size,$free_list)//再次申请分块,主要是回收垃圾获取的分块
            if(obj==NULL)
                allocation_fail()
            
        obj.ref_cnt=1 
        //mutator不会进行计数更新,只在创建对象时,有个标记1,所以需要zct表扫描。
        return obj
    }
    
    scan_zct(){
        for(r:$roots) //所有活动对象,计数增加;从这看,计数器的宽度问题还在
            (*r).ref_cnt++
        
        for(obj:$zct)//检查zct表,遍历之后,计数仍未0,则该对象真的是垃圾了
            if(obj.ref_cnt==0)
                remove($zct,obj)//回收垃圾
                delete(obj)     
        for(r:$roots) //恢复之前的引用计数
            (*r).ref_cnt--
    }
    delete(obj){
        for(child:children(obj))//将垃圾对象中的子对象的引用减量
            (*child).ref_cnt--
            if((*child).ref_cnt==0)
                delete(*child)
        reclaim(obj)
    }
    

    优点:延迟了根引用的计数,将垃圾一并回收,通过延迟,减轻了因根频繁变化而导致的计数器增减所带来的额外负担。
    缺点:延迟计数器值增减,致使垃圾不能马上回收,并压迫堆,也就失去了引用计数法的一大优点–可即刻回收垃圾;另scan_zct()函数导致最大暂停时间延长。

    Sticky引用计数法:对计数器的改进处理
    其解决的是计数器占用空间过大的问题,比如采用5位的计数器,这会带来计数溢出问题,通过增加对计数器的管理,来解决该问题;此外,之所以可以采用该问题,是因为实际中极高引用数的情况很少,一般引用数不大,甚至大多对象创建,之后就释放了。

    计数器溢出处理:

    1. 什么也不做,溢出就溢出了,也就无法回收该对象,正如之前所说,因为溢出的对象较少,另外,溢出的对象在程序中占有较高地位,成为垃圾的可能性也较低,所以问题也不大…但终究是有问题的。
    2. 使用GC标记-清除算法进行管理,该后援会刷新对象的引用计数,即活动对象仍有引用,垃圾对象引用数为0,这保证可以回收之前引用溢出无法回收的垃圾;并且该后援可以处理循环引用问题,因为遍历根了嘛,不在根下,计数被置0后,没有增长,即是垃圾。但标记-清除算法是要花费更多时间的,所以吞吐量也会相应减少。

    GC标记-清除算法管理引用计数:

    1. 一开始就把所有对象的计数器值设为0
    2. 不标记对象,而是对计数器进行增量操作
    3. 为了对计数器进行增量操作,算法对活动对象进行了布置一次的搜索
    mark_sweep_for_counter_overflow(){
        reset_all_ref_cnt()//将计数清零,方便处理计数溢出的对象
        mark_phase() //更新引用计数
        sweep_phase() //回收垃圾
    }
    mark_phase(){//dfs方式搜索
        for(r:$roots) //所有活动对象入栈,以更新其计数
            push(*r,$mark_stack)
           
        while(is_empty($mark_stack)==FALSE)
            obj=pop($mark_stack)
            obj.ref_cnt++ //更新计数
            if(obj.ref_cnt==1) //每个对象的子对象只遍历一次,就是扫描整个树一次
                for(child: children(obj))//若被引用,还会入栈
                    push(*child,$mark_stack)
    }
    sweep_phase(){
        sweeping = $heap_top
        while(sweeping<$heap_end)//还是通过遍历对象,回收的,费时
            if(sweeping.ref_cnt==0)//回收垃圾
                reclaim(sweeping)
            sweeping+=sweeping.size
    }
    

    1位引用计数法:

    该算法更激进了些,是Sticky引用计数法的特殊情况,其作者认为,大多对象,在创建后,就会立马死亡,所以可以只用1位计数器。
    这里的计数器称为tag更为合理,这里对象只有两种情况:0-一定不是垃圾(UNIQUE),1-可能是垃圾(MULTIPLE)。

    指针通常默认4个字节对齐,所以没法利用低2位,可以利用该性质,就能拿出1位作为计数tag,用作内存管理。为什么指针4b对齐,没法利用低2位?
    经询问本科时的师兄,指针指向的是数据是4B对齐,指针变化都是4倍进行的,所以最低两位,都是0。这里吐槽一下该书!
    这里用这个特性,就要求系统数据必须4B对齐。巧是巧,但就是对系统有要求,反而不好。

    1位引用计数法也是在更新指针的时候进行内存管理的,不过它不像以往那样要引用对象来更新指针,而是通过复制某个指针来更新指针。
    次改进,只需将mutator的update_ptr()更换成copy_str()即可。

    copy_ptr(dest_ptr,src_ptr){
        //原对象丢失一个引用,
        //之前状态unique或者multiple,若是unique则可进行回收
        delete_ptr(dest_ptr)
        *dest_ptr=*src_ptr
        set_multiple_tag(dest_ptr)//此时一定是multiple
        if(tag(src_ptr)==UNIQUE)
            set_multiple_tag(src_ptr)
    }
    delete_ptr(ptr){
        if(tag(ptr)==UNIQUE)//回收
        reclaim(*ptr)
    }
    

    优点:不容易出现告诉缓存缺失,应该是不会像标记-清除算法那样遍历对象,就会造成较多的不在缓存中的对象,从而访问内存,增加时间;对象元数据不需要计数器,所以节省内存空间。
    缺点:跟Sticky引用计数算法基本一样,在1位计数器下,可能出现大量对象计数器溢出的情况,这会给堆带来较大负担,即垃圾压迫堆。

    部分标记-清除算法:引用计数的后援,负责循环引用垃圾的处理

    该算法针对之前的通过标记-清除算法要进行全部搜索的后援,进行了优化,提出一中部分标记-清除算法,将垃圾限定可能产生垃圾的对象集中。
    这里定义了四种颜色,占用2位空间:

    1. 黑:绝对不是垃圾的对象(对象产生时的初始颜色)
    2. 白:绝对是垃圾的对象
    3. 灰:搜索完毕的对象
    4. 阴影(hatch):可能是循环垃圾的对象

    该算法是较为复杂的,可通过如下图示理解,其思想:
    0. 对于循环引用,环节点就在外部引用那个点,即其计数是大于2的,所以通过遍历确定外部引用的节点,已被断开即可。

    1. 确定方法就是颜色标记法,有对象释放,引用减少,其就可能时循环引用的节点,标记为阴影,并不马上确定是否时循环引用垃圾;
    2. 在空闲链表上的分块无法满足时,就会启动该标记-清除算法,扫描所有阴影对象,这里要进行多次扫描,因为颜色要经历几次变化,首先从阴影到灰色,并对子对象的引用数减量;知道所有的阴影对象便会灰色;
    3. 接着,再次遍历hatch_queue,这时都是灰色的,根据其引用数,确定是否是白色,引用数为0,则是垃圾,否则是活动对象,置为黑色。
      注意这里是减量是对其子对象操作的,若是环,则减量操作会作用到最终的起点上,并形成一个环的逻辑,为什么不对该对象本身减量,见bad_paint_gray(obj)。

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    dec_ref_cnt(obj){
        obj.ref_cnt--
        if(obj.ref_cnt==0)
            delete(obj)
        else if(obj.color!=HATCH)
            obj.color=HATCH
            enquere(obj,$hatch_queue)
    }
    new_obj(size){
        obj=pickup_chunk(size)
        if(obj!=NULL)//新创建的对象是黑色的
            obj.color=BLACK
            obj.ref_cnt=1
            return obj
        else if(is_empty($hatch_queue)==FALSE)
            scan_hatch_queue()//分块失败,则要扫描,清理垃圾
            return new_obj(size)
            //递归进行的,扫描一次不行么?应该可以,这里也只需一次递归吧,
            //再次递归,scan_hatch_queue,没有变化啊,该处理的已经处理完了
        else
            allocation_fail()
    }
    scan_hatch_queue(){
        obj=dequeue($hatch_queue)
        if(obj.color==HATCH)//或是嘤嘤的,则要进行判断,是否是循环引用垃圾
            paint_gray(obj)//标记访问过的
            scan_gray(obj)//扫描访问过的,并确定出白色,即垃圾
            collect_white(obj)//回收垃圾
        else if(is_empty($hatch_queue)==FALSE)
            scan_hatch_queue()//递归进行,将hatch_queue处理完
    }
    paint_gray(obj){
        if(obj.color==(BLACK|HATCH))
            obj.color=GRAY
            for(child:children(obj))
            //减量操作在子对象上,这样可以表示循环,a->b,b->a,最后操作在自己本身,可以确定是循环
            //若对自己减量,则无法区别,a->b,b->c 和a->b,b->a
                (*child).ref_cnt--
                paint_gray(*child)
    }
    scan_gray(){
        if(obj.color==GRAY)
            if(obj.ref_cnt>0)//活动的对象,其子对象多是活动的
                paint_black(obj)
            else //循环中的垃圾,回收
                obj.color=WHITE
                for(child:children(obj))//遍历子对象,将垃圾标为白色,活动对象,置黑,待下回扫描
                    scan_gray(*child)
    }
    paint_black(obj){//将活动对象标黑
        obj.color=BLACK
        for(child:children(obj))
            (*child).ref_cnt++
            if((*child).color!=BLACK)
                paint_black(*child)
    }
    collect_white(obj){//对白色对象的子对象进行减量操作,并回收白色对象
        if(obj.color==WHITE)
            obj.color=BLACK
            for(child:children(obj))
                collect_white(*child)
            reclaim(obj)
    }
    
    

    扫描hatch_queue时,为什么对子对象减量,而不是本身,见如下代码
    减量操作在子对象上,这样可以表示循环,a->b,b->a,最后操作在自己本身,可以确定是循环;若对自己减量,则无法区别,a->b,b->c 和a->b,b->a。可见下图的例子。

    bad_paint_gray(obj){
        if(obj.color==(BLACK|HATCH))
            obj.ref_cnt--
            obj.color=GRAY
            for(child:children(obj))
                bad_paint_gray(*child)
    }
    

    在这里插入图片描述
    评价:部分标记-清除算法因为从队列搜索对象所付出的成本太大了,队列中的对象是候选垃圾,所以搜索的对象不在少数;且因为颜色标记,所以需要遍历3次(mark_gray、scan_gray、collect_white),所以这也大大增加内存管理时间,即引用计数法的一大优点,最大暂停时间不复存在了。

    以上内容为读书笔记,参考资料《垃圾回收的算法与实现》。

    展开全文
  • 引用计数法 引用计数法优缺点 引用计数法的简单缺点实例 可达性分析法 可以作为GCRoot的对象

    引用计数法

    在这里插入图片描述

    引用计数法优缺点

    在这里插入图片描述

    引用计数法的简单缺点实例

    在这里插入图片描述

    可达性分析法

    在这里插入图片描述

    可以作为GCRoot的对象

    在这里插入图片描述

    展开全文
  • 引用计数法 关于引用计数法,我们可以先看一段wiki上的描述: As a collection algorithm, reference counting tracks, for each object, a count of the number of references to it held by other objects. If ...
  • 垃圾回收-- 引用计数法

    千次阅读 2019-06-29 23:35:11
    引用计数法 引用计数法,最重要的就是计数器,记录有多少引用该对象 引用计数法与mutator 的执行密切相关,在mutator 的处理过程中通过增减计数器的值来进行内存管理, 在分配和更新对象时会发生计数的变化 更新操作...
  • 关于引用计数法的循环引用问题

    千次阅读 2020-03-11 18:02:34
    现在JVM大多不采用引用计数法 进行GC,很大程度上是因为引用计数法不能解决循环引用的问题。 如下代码 public class TestClass { private Object ref; public static void main(String[] args) { TestClass o1...
  • GC算法-引用计数法

    2020-04-05 18:37:17
    GC算法-引用计数法 概述 引用计数法又是什么鬼呢? 顾名思义, 对对象的引用进行计数. 通过记录每个对象被引用的次数, 来确定这个对象是否可以被回收. 实现 首先, 对对象的引用数量进行管理, 什么时候会更新呢? 创建...
  • 行业分类-作业装置-基于引用计数法的新型垃圾回收算法.7z
  • 啥是引用计数法 顾名思义,就是当一个对象被引用的时候进行数字计数,当增加一次引用的时候计数+1,当删除一个对象的引用时-1;当一个对象的引用变成0的时候,就可以被回收了 出现的问题 请先看代码: public ...
  • 引用计数法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。 引用计数法的实现简单,判定效率也很高,在大...
  • 引用计数法和根搜索算法 如何判断对象是否存活 引用计数法 概念 引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾。这种方法的缺点就是不能检测到环的存在。 首先需要声明,至少主流的Java虚拟机...
  • 深入JVM 引用计数法

    千次阅读 2019-02-21 14:42:50
    ——引用计数法   前言:给对象添加一个引用计数器,每当一个地方引用它时,计数器加1,每当引用失效时,计数器减少1.当计数器的数值为0时,也就是对象无法被引用时,表明对象不可在使用,这种方法实现简单,效率...
  • 垃圾标记阶段:对象存活判断 堆里存放着几乎所有的Java对象实例,在GC执行垃圾回收之前,首先需要区分出内存中那些是存活对象,哪些是已经死亡的对象。只有被标记为已经死亡的对象...引用计数法(ReferenceCounting).
  • 引用计数法(Reference Counting) 由1960年GeorgeE.Collins提出。引用计数法为每个对象引入技术器,当对象被引用(被其他对象指向)时技术器+1,当技术器为0时表示对象不可达则被视为垃圾处理。优点:与不同标记-...
  • 引用计数法: 给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。 虽然引用计数法有许多成功的案例有很多,但是...
  • 让各对象知道自己的”人气指数“,从而让没有人气的对象自己消失,这就是引用计数法(Reference Counting),它是George E.Collins 于1960年研究出来的。 (60年左右可谓是 垃圾回收算法的元年)。 引用计数法引入...
  • 引用计数法和可达性分析算法

    千次阅读 2018-05-23 10:08:10
    一、引用计数法给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不能再被使用的。引用计数法实现简单,判定效率也很高,但是它很难...
  • GC_3_引用计数法

    千次阅读 2017-04-03 10:28:55
    3 引用计数法   GC是一种,释放怎么都无法被引用的对象的机制。可以让所有对象事先记录下有多少程序引用自己,让各对象知道自己的人气指数,从而让没有人气的对象自己消失,这就是引用计数法(Reference Counting...
  • 引用计数法意如了一个概念,那就是“计数器”,计数器表示的是对象的人气指数, 也就是有多少程序引用了这个对象(被引用书),计数器是无符号的整数。 在引用计数法中并没有mutator明确启动GC的语句。引用计数法与...
  • 10 引用计数法

    2020-06-14 23:35:10
    客观的说,引用计数算法的实现简单,判定的效率很高,在大部分的情况下是一个不错的算法. 默认标记次数 = 15次,当标记 = 0,gc直接回收 对象被引用的话,就会 +1,然后放到 s0或者s1区,如果还是被频繁使用,那么...
  • 垃圾回收的五种算法——引用计数法 1.引用计数法 1.1简介 引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、 内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其 ...
  • 垃圾对象检测主要有两种算法:引用计数法和可达性分析法(引用链),这里主要研究下这两种算法。1.引用数法 引用计数法师垃圾收集的早期策略,在这中方法中,堆中每个对象都有一个引用计数,每当有一个地方引用他时...
  • 概述JVM很重要。尤其是GC算法。程序计数器、虚拟机栈、本地方法栈。这几个区域完全不用管回收问题,因为方法结束或者线程结束的时候他们所占用的内存就自然跟着一起释放了,3个区域随线程...引用计数法(ReferenceCo...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 59,728
精华内容 23,891
关键字:

引用计数法