jvm的垃圾收集器与内存分配策略

概述:

 

    jvm的内存分为线程隔离的虚拟机栈、程序计数器、本地方法栈和共享线程的堆和方法区,由于线程隔离的内存区域随着线程结束而消亡所以在java世界里垃圾回收主要是针对堆中的对象回收,因为在对象在堆中的内存大小可能完成不一致不像虚拟机栈那样固定,这部分内存的分配和回收是动态的所以垃圾收集器主要收集的是堆中的对象。

1.如何判断对象的存活算法

     1.1 引用计数法-

           在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能再被使用的,它的原理简单,判定效率也很高。缺点引用计数就很难解决对象之间相互循环引用的问题。

    1.2 可达性分析算法(GC Root)

           通过例如虚拟机栈中的引用对象做为根节点,依据根节点对象中的引用关系向下搜索,搜索过程的路径称为引用链。

           根对象定义:

              虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。

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

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

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

             Java虚拟机内部的引用,如基本数据类型对应的Class对象,

             一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加  载器。·

            所有被同步锁(synchronized关键字)持有的对象。·反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

    1.3 引用

         强引用:Object obj=new Object();

         软引用:还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存溢出异常。

         弱引用:它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生为止。

        虚引用:它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例,系统通知作用。

  1.4 对象生存还是死亡

         如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。假如对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,那么虚拟机将这两种情况都视为“没有必要执行”。如果对象有必要执行那么会进入F-Queue的队列之中由Finalizer线程去执行它们的finalize()方法。finalize方法是拯救对象继续存活的一种方法。

1.5 垃圾收集方法

        对象消亡的角度出发,垃圾收集算法可以划分为“引用计数式垃圾收集”(Reference Counting GC)和“追踪式垃圾收集”(Tracing GC)两大类,这两类也常被称作“直接垃圾收集”和“间接垃圾收集”。

1.6 分带收集理论

      1)弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。

      2)强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡。

       把分代收集理论具体放到现在的商用Java虚拟机里,设计者一般至少会把Java堆划分为新生代(Young Generation)和老年代(Old Generation)两个区域。

       进行一次只局限于新生代区域内的收集(Minor GC),但新生代中的对象是完全有可能被老年代所引用的,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的正确性。为了不遍历整个老年代在只需在新生代上建立一个全局的数据结构(该结构被称为“记忆集”,Remembered Set),这个结构把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描。

  名词定义:

        新生代收集(Minor GC/Young GC):指目标只是新生代的垃圾收集。

       老年代收集(Major GC/Old GC):指目标只是老年代的垃圾收集。目前只有CMS收集器会有单独收集老年代的行为。另外请注意“Major GC”这个说法现在有点混淆,在不同资料上常有不同所指,读者需按上下文区分到底是指老年代的收集还是整堆收集。   

      混合收集(Mixed GC):指目标是收集整个新生代以及部分老年代的垃圾收集。目前只有G1收集器会有这种行为。

      整堆收集(Full GC):收集整个Java堆和方法区的垃圾收集。

2.垃圾收集算法

     2.1 标记-清除算法-CMS

            首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回收所有未被标记的对象。缺点:执行效率不稳定,空间碎片化验证。

   2.2 标记-复制算法(新生代)

            它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

            Appel式回收的具体做法是把新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次分配内存只使用Eden和其中一块Survivor,发生垃圾搜集时,将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上。HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1,也即每次新生代中可用内存空间为整个新生代容量的90%(Eden的80%加上一个Survivor的10%),只有一个Survivor空间,即10%的新生代是会被“浪费”的。

           分配担保:另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象,这些对象便将通过分配担保机制直接进入老年代,这对虚拟机来说就是安全的。

2.3 标记-整理算法(老年代)-parallel scavenge

         标记-整理中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。

        HotSpot虚拟机里面关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的࿰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值