Java回收机制专刊

Java的回收机制,我们需要了解的是(1)什么样的对象需要回收(如何判断其需要回收)(2)回收方法(3)gc的执行机制(也就是什么条件下执行minor gc ,full gc)

1~4转载自https://www.cnblogs.com/prophet-it/p/6498275.html,但是其中对于gc执行机制和新生代老年代这部分说的不清楚,我做了相关补充!

1.java的内存

java的内存结构分为

  • 堆 (是gc的主要区域) 线程共享,主要是用于分配实例对象和数组
  • 方法区 线程共享 用于储存被虚拟机加载的类的信息,静态变量 常量和编译后的.class字节码
  • 栈 线程私有,它的生命周期和线程相同,又分成 虚拟机栈和本地方法栈,只有它会报 StackOverFlowError,栈深度超标
  • 程序计数器 线程私有,线程之间不相互影响,独立存取;
    以上部分,线程私有是不会发生gc.并且他们是随线程生随线程灭,即程序计数器 本地方法栈和虚拟机栈

2.GC回收机制--判断是否可以gc

  • 引用计数算法
    原理:通过一个计数器对对象进行计数,对象被引用时+1,引用失效时-1;当计数为0时则说明可以被回收;
    缺点:很难解决对象的相互循环引用问题
  • 可达性分析算法
    Java虚拟机所采用的算法;
    原理:通过一些列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
    那么哪些对象可以被称为gc roots呢----虚拟机栈(栈中的本地变量列表)/方法区静态属性/方法区常量引用/本地方法栈中JNI 所引用的的对象都是可以作为 gc roots的

3.GC回收机制--如何回收

  • 标记清除算法
    清除算法分成2个阶段--标记和清除; 标记阶段对所有存活的阶段进行标记,标记完成后,再扫描整个空间未标记对象,直接回收不存活的对象.
    优点:大多数情况下比较高效,缺点是会造成内存碎片,碎片太多导致后面过程中对大内存的分配无足够空间时而提前猝发一次垃圾回收动作;
  • 复制算法
    将可用内存将容量划分成大小相等的2块,每次清理时将其中A内存还存活的对象复制到B内存里面,然后再把A中清理掉;
    优点高效且并不产生碎片,缺点牺牲了一半的内存为代价
    适用存活对象少,回收对象多
  • 标记整理算法
    该算法标记阶段和标记清除算法一样,完成标记后它不是直接清理可回收对象,而是将存活对象都向一端移动最后清理掉端边界意外的内存;
    适用于存活对象多,回收对象少的情况
  • 分代收集算法
    整合了复制算法和标记整理算法,根据新生代和老年代的不同特性采取上面的不同算法
    新生代 生命周期短,每次回收时都有大量垃圾对象需要回收 复制算法
    老年代 每次只有少量的对象需要回收 标记整理算法

深入理解分代回收算法 Survivor(幸存者) Eden (谷歌翻译为伊甸园)

  • 复制算法中内存划分其实并不是按照1:1来划分老年代和新生代,,而是按照8:1:1分一个大的Eden区和两个小的survivor的空间
  • 为什么需要2个Survivor区 新生代一般经历15次Gc就可以移到老年代.当第一次gc时,我们可以把Eden的存活对象放入Survivor A空间,第二次Gc时,Survivor A也要使用复制算法,存活对象放到Survivor B上,第三次gc时,又将Survivor B对象复制到Survivor A上如此循环往复;
  • 为什么Eden这么大,因为新生代中存活的对象,需要转移的Survivor 的对象不多,算是缓解了复制算法的缺点;

4.GC回收机制--gc的执行机制

  • Minor GC
    当新对象生成并且在Eden申请空间失败时就会触发Scavenge GC;Eden区的gc会比较频繁
  • Full GC
    是对整个堆进行清理,要比Scavenge GC要慢,什么情况要进行Full GC呢,如下四种:
    持久代被写满
    System.gc调用
    老年代被写满
    上一次GC之后Heap的各域分配策略动态变化

持久代:
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class

5. 补充

(1)一般将堆分为新生代和老年代

       新生代中采用的收集算法:复制算法。算法的思想是将可用内存分为大小相等的两块,每次使用其中一块,当一块内存用完了,就将还存活的对象分到另一块。然后把使用过的内存空间一次进行清理。这种算法缺点会明显,就是会浪费一半的空间。而根据IBM研究表明,新生代中98%的对象朝生夕死,所以不需要按照1:1进行分配,而是按照内存分为一块较大的Eden空间和两块较小的Survivor空间(from和to两个),每次使用Eden和其中一个Survivor。当回收时,将Eden和其中一块Survivor中还存活着的对象一次性复制到另一块Survivor中,然后清理Eden和刚才用过的Survivor空间。一般默认的比例为:Eden:from:to=8:1:1。注:可通过-XX:SurvivorRatio=i来设置,默认i=8。

       注意:当Survivor空间不够时,需要依赖其他内存(老年代)进行分配担保。内存的分配担保:如果另一块Survivor空间没有足够的内存空间存放上一次新生代收集下来的存活对象,那么这些对象将直接通过分配担保机制进入老年代。

       老年代中采用的收集算法:标记-整理算法。算法思想:首先标记需要回收的对象,然后让所有存活的对象向一端移动,然后直接清理掉边界以外的内存。

(2)什么时候minor gc,full gc

Minor GC触发条件:当Eden区满时,触发Minor GC。

Full GC触发条件:

(1)调用System.gc时,系统建议执行Full GC,但是不必然执行

(2)老年代空间不足

(3)方法去空间不足

(4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存

(5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值