文章目录

  • 一、什么是垃圾回收
  • 二、为什么需要垃圾回收
  • 三、java中的四种引用类型
  • 四、垃圾识别机制
    • 1.引用计数算法
    • 2.可达性分析算法
  • 五、finalize()赋予对象重生
    • 流程图(finalize()存在时)
  • 六、四种垃圾回收算法
    • 标记清除算法
    • 标记整理算法
    • 复制算法
    • 分代收集算法
      • Minor GC和Full GC区别

一、什么是垃圾回收

java相较于c、c++语言的优势之一是自带垃圾回收器,垃圾回收是指不定时去堆内存中清理不可达对象。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,程序员唯一能做的就是通过调用System.gc 方法来建议执行垃圾收集器,但其是否可以执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。

二、为什么需要垃圾回收

如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。

三、java中的四种引用类型

强引用

Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收
obj = null;  //手动置null,可以通过System.gc方法进行回收处理

我们一般声明对象时虚拟机生成的引用,强引用环境下,垃圾回收时需要严格判断当前对象是否被强引用,如果被强引用,就说明他不是垃圾,则不会被垃圾回收。

软引用
软引用一般被做为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在发生OutOfMemory时,肯定是没有软引用存在的。

弱引用
弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,**被弱引用关联的对象只能生存到下一次GC发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会回收掉该类对象。**弱引用对象在回收时会被放入引用队列(ReferenceQueue)。

虚引用
虚引用被称为幽灵引用或幻象引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得对象实例。任何时候都可能被回收,一般用来跟踪对象被垃圾收集器回收的活动,起哨兵作用。必须和引用队列(ReferenceQueue)联合使用。

这些概念可能有点抽象,不过这四种引用具有不同的垃圾回收时机应该是很清楚的。我们会发现,引用的强度从强、软、弱、虚依次递减,越往后的引用所引用的对象越容易被垃圾回收。

四、垃圾识别机制

1.引用计数算法

引用计数算法是判断对象是否存活的算法之一:它给每一个对象加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能被使用的,即将被垃圾回收器回收。

缺点:
1.他需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
2.无法解决对象减互相循环引用的问题。即当两个对象循环引用时,引用计数器都为1,当对象周期结束后应该被回收却无法回收,造成内存泄漏。

public class GcTest {public static void main(String[] args) {       MyObject myObject_1 = new MyObject();       MyObject myObject_2 = new MyObject();                myObject_1.instance = myObject_2;        myObject_2.instance = myObject_1;myObject_1 = null;        myObject_2 = null;  System.gc();    }  // 对象循环引用,用引用计数算法时,无法回收这两个对象

2.可达性分析算法

目前主流使用的都是可达性分析算法来判断对象是否存活。算法基本思路:以“GC Roots”作为对象的起点,从此节点开始向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

哪些对象可作为GC Roots?
虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(Native方法)引用的对象;
活跃线程的引用对象。

五、finalize()赋予对象重生

finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。

在可达性分析算法中被标记为不可达的对象,也不一定是一定会被回收,它还有第二次重生的机会。每一个对象在被回收之前要进行两次标记,一次是没有关联引用链会被标记一次,第二次是判断该对象是否覆盖finalize()方法,如果没有覆盖则真正的被定了“死刑”。

代码实现

public class FinalizeTest {public static FinalizeTest ft;/*** 用于判断对象是死亡还是存活*/public static void judge(){if(ft == null){System.out.println("i am dead");}else{System.out.println("i am alive");}}public static void main(String[] args) throws InterruptedException {ft = new FinalizeTest();// 将引用指向null,那么对象就没有任何关联了ft = null;// 触发一次gcSystem.gc();// 因为Finalizer线程的优先级低,因此sleep 1秒后再看结果Thread.sleep(1000);//因为FinalizeTest对象覆盖了finalize方法,并在该方法中重新建立与引用的关联,所以对象会复活judge();//下面的代码和上面的一模一样,但是对象不会再复活了,因为finalize方法最多执行一次ft = null;System.gc();Thread.sleep(1000);judge();}@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("执行finalize方法");// 对象复活的关键:重新建立与引用的关联ft = this;}
}

流程图(finalize()存在时)

六、四种垃圾回收算法

确认完垃圾之后肯定要想办法回收垃圾。回收垃圾主要有下面四种方法:标记清除算法、标记整理算法、复制算法、分代收集算法。

标记清除算法

算法思路:算法分为“标记”和“清理”两个步骤,首先标记处所有需要回收的对象,在标记完成后再统一回收所有被标记的对象。

缺陷:
1.标记和清理的两个过程效率都不高;
2.容易产生内存碎片,碎片空间太多可能导致无法存放大对象。

适用于存活对象占多数的情况。

标记整理算法

算法思路:标记过程和标记-清理算法一样,而后面的不一样,它是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

复制算法

算法思路:将可用内存划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完后,就将还存活的对象复制到另一块去,然后再把已使用过的内存空间一次清理掉。

缺陷:
可用内存缩小为了原来的一半
算法执行效率高,适用于存活对象占少数的情况。

分代收集算法

当前大多数垃圾收集都采用的分代收集算法,这种算法并没有什么新的思路,只是根据对象存活周期的不同将内存划分为几块,每一块使用不同的上述算法去收集。在jdk8以前分为三代:年轻代、老年代、永久代。在jdk8以后取消了永久代的说法,而是元空间取而代之。

在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
老年代
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记-清除-压缩”算法进行回收。

Minor GC和Full GC区别

新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。
老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。


年轻代分为伊甸园区和幸存区,幸存区分为from和to区。每次执行GC操作,会将伊甸园区和from区存活的对象放到to区(如果to区不够,则直接进入老年代),然后将from区和to区的职责交换(from区变为to区,to区变为from区,谁空谁是to区)。

新生代中的对象98%都是朝生夕死的,因此把新生代分为较大的一块Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor(此处Survivor区也叫From区,另一块空的未使用的空间叫To区,From和To区是会交换的,保证空的总是To区)。

当Eden区没有足够的空间分配时,会进行一次Minor GC,Eden区大部分对象都被回收,而Eden区和From区存活的对象会放入到To区,然后From和To区进行交换。(如果To区空间不够,直接进入老年代)

以下几种情况会进入老年代。

1、 大对象
大对象就是指需要大量连续内存空间的对象,最典型的就是那种很长的字符串和数组。大对象会直接进入到老年代,这样做的目的主要是为了避免新生代发生大量的内存复制(大对象的复制成本较高)。

2、长期存活的对象
虚拟机给每个对象都定义了一个对象年龄计数器。每当进行一次Minor GC,年龄就增加1岁,当年龄超过一定值时(默认是15,可以通过参数配置),就进入到老年代。

动态对象年龄判断
虚拟机并不要求对象年龄一定要到达15岁才进入到老年代。如果Survivor空间中有某年龄相同的所有对象大小总和大于Survivor空间的一半,则年龄大于等于该年龄的对象就会直接进入老年代。

JVM中的垃圾回收机制相关推荐

  1. Java Jvm 中的垃圾回收机制中的思想与算法 《对Java的分析总结》-四

    Java中的垃圾回收机制中的思想与算法 <对Java的分析总结>-四 垃圾回收机制 中的思想与算法 引用计算法 给对象中添加一个引用计数器,每当一个地方引用它的时候就将计数器加1,当引用失 ...

  2. java和net共同点,Java和.NET中的垃圾回收机制比较

    相同点: 都采用了分代的机制. 都支持并发GC. 都没有采用引用计数方式,而是采用了追踪技术. .NET中,可以通过代码GC.Collect() 强制要求CLR进行垃圾回收(由于垃圾回收是异步的,CL ...

  3. 浅谈V8引擎中的垃圾回收机制

    浅谈V8引擎中的垃圾回收机制 这篇文章的所有内容均来自 朴灵的<深入浅出Node.js>及A tour of V8:Garbage Collection,后者还有中文翻译版V8 之旅: 垃 ...

  4. 一篇文章搞定java中的垃圾回收机制面试题

    一篇文章搞定java中的垃圾回收机制面试题 任何语言在运行过程中都会创建对象,也就意味着需要在内存中为这些对象在内存中分配空间,在这些对象失去使用的意义的时候,需要释放掉这些内容,保证内存能够提供给新 ...

  5. 简述python垃圾回收机制_python中的垃圾回收机制简述

    2020年12月5日21:47:35 王凯玉 python中的垃圾回收机制 引用计数 # 引用计数 引用计数是编程语言中的一中内存管理技术,可以将资源的被引用次数保存起来. 当引用计数为0时,资源将被 ...

  6. js中的垃圾回收机制

    js中的垃圾回收机制 1.什么是堆.栈 一种数据结构,栈有先进后出的特性, 堆是用来存放复杂数据类型的地址(栈用来存放它的引用) 2.执行上下文与作用域链 执行上下文:全局执行上下文.函数执行上下文. ...

  7. Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略

    V8 实现了准确式 GC,GC 算法采用了分代式垃圾回收机制.因此,V8 将内存(堆)分为新生代和老生代两部分. 一.前言 V8的垃圾回收机制:JavaScript使用垃圾回收机制来自动管理内存.垃圾 ...

  8. JVM GC(垃圾回收机制)

    在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当st ...

  9. JVM GC(垃圾回收机制)Minro GC,Major GC/Full GC

    在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行.当st ...

最新文章

  1. MATLAB_4-形态学_腐蚀_膨胀_灰度图的腐蚀以及膨胀_开运算_闭运算_文章末尾有几个素材例子
  2. 全球顶级设计师云集天猫双11 超1000款时尚大牌新品首发
  3. halcon例程讲解_跟我学机器视觉-HALCON学习例程中文详解-开关引脚测量
  4. 如何编写nopCommerce插件
  5. 闲谈简单设计(KISS)疑惑
  6. P3302-[SDOI2013]森林【主席树,LCA,启发式合并】
  7. Spring Social入门
  8. pytest测试实战 电子书_电子书丨Selenium 3+Python 3自动化测试项目实战:从菜鸟到高手...
  9. php中图片怎么加样式,html5实现各种图片样式实例用法汇总
  10. Android开发笔记(一百三十一)水波图形与水波动画
  11. CABasicAnimation 按home键后台之后,再切回来动画就停止
  12. Linux下C语言编程风格和规范
  13. 学习Bash shell编程资料推荐
  14. 开票服务器系统是否可以抵扣,开票系统服务费抵扣的账务处理
  15. SketchUp2016如何安装插件
  16. 字体反扒 ---汽车之家(文字)
  17. ​Spring Cloud:统一异常处理
  18. ssh常用命令50条
  19. VMware vGPU服务器配置
  20. 10个让你早起的技巧

热门文章

  1. 傅里叶变换、离散余弦变换、拉普拉斯变换、Z变换
  2. Scala中使用ansj分词库编写spark中文版WordCount
  3. GD32450i-EVAL学习笔记 19 - USB FS 数据传输
  4. 杰理之 盘/TF 卡升级【篇】
  5. .NET WebApi调用微信接口Https请求工具类
  6. MyBits使用基础
  7. 【ABBYY FineReader】pdf文件很清晰但是复制或导出都是乱码
  8. CSS实现图片与文本的居中对齐的常见方式
  9. MySQL 占用过高CPU时的优化手段
  10. 微服务实战|微服务网关Zuul入门与实战