一:概述

  在这篇文章中《Jvm运行时数据区》介绍了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈,3个区域随着线程的生存而生存的。内存分配和回收都是确定的。随着线程的结束内存自然就被回收了,因此不需要考虑垃圾回收的问题。而Java堆和方法区则不一样,各线程共享,内存的分配和回收都是动态的。因此垃圾收集器所关注的都是这部分内存。

  接下来我们就讨论Jvm是怎么回收这部分内存的。在进行回收前垃圾收集器第一件事情就是确定哪些对象还存活,哪些已经死去。下面介绍两种基础的回收算法。

1.1 引用计数算法

  给对象添加一个引用计数器,每当有一个地方引用它时计数器就+1,当引用失效时计数器就-1,。只要计数器等于0的对象就是不可能再被使用的。

  此算法在大部分情况下都是一个不错的选择,也有一些著名的应用案例。但是Java虚拟机中是没有使用的。

  优点:实现简单、判断效率高。

  缺点:很难解决对象之间循环引用的问题。例如下面这个例子

Object a = new Object();
Object b = new Object();
a=b;
b=a;
a=b=null; //这样就导致gc无法回收他们。  

1.2 可达性分析算法

  通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有使用任何引用链时,则说明该对象是不可用的。

  主流的商用程序语言(Java、C#等)在主流的实现中,都是通过可达性分析来判定对象是否存活的。

  通过下图来清晰的感受gc root与对象展示的联系。所示灰色区域对象是存活的,Object5/6/7均是可回收的对象

 在Java语言中,可作为GC Roots 的对象包括下面几种

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中静态变量引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈(即一般说的 Native 方法)中JNI引用的对象

 优点:更加精确和严谨,可以分析出循环数据结构相互引用的情况;

 缺点:实现比较复杂、需要分析大量数据,消耗大量时间、分析过程需要GC停顿(引用关系不能发生变化),即停顿所有Java执行线程(称为"Stop The World",是垃圾回收重点关注的问题)。

二:引用

 在jdk1.2之后,Java对引用的概念进行了扩充,总体分为4类:强引用、软引用、弱引用、虚引用,这4中引用强度依次逐渐减弱。

  • 强引用:指在代码中普遍存在的,类似 Object obj = new Object(); 这类的引用,只有强引用还存在,GC就永远不会收集被引用的对象。
  • 软引用:指一些还有用但并非必须的对象。直到内存空间不够时(抛出OutOfMemoryError之前),才会被垃圾回收。采用SoftReference类来实现软引用
  • 弱引用:用来描述非必须对象。当垃圾收集器工作时就会回收掉此类对象。采用WeakReference类来实现弱引用。
  • 虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响, 唯一目的就是能在这个对象被回收时收到一个系统通知, 采用PhantomRenference类实现

2.1 判断一个对象生存还是死亡

  宣告一个对象死亡,至少要经历两次标记。

  1、第一次标记

  如果对象进行可达性分析算法之后没发现与GC Roots相连的引用链,那它将会第一次标记并且进行一次筛选。

  筛选条件:判断此对象是否有必要执行finalize()方法。

  筛选结果:当对象没有覆盖finalize()方法、或者finalize()方法已经被JVM执行过,则判定为可回收对象。如果对象有必要执行finalize()方法,则被放入F-Queue队列中。稍后在JVM自动建立、低优先级的Finalizer线程(可能多个线程)中触发这个方法;  

  2、第二次标记

  GC对F-Queue队列中的对象进行二次标记。

  如果对象在finalize()方法中重新与引用链上的任何一个对象建立了关联,那么二次标记时则会将它移出“即将回收”集合。如果此时对象还没成功逃脱,那么只能被回收了。

  3、finalize() 方法

  finalize()是Object类的一个方法、一个对象的finalize()方法只会被系统自动调用一次,经过finalize()方法逃脱死亡的对象,第二次不会再调用;

  特别说明:并不提倡在程序中调用finalize()来进行自救。建议忘掉Java程序中该方法的存在。因为它执行的时间不确定,甚至是否被执行也不确定(Java程序的不正常退出),而且运行代价高昂,无法保证各个对象的调用顺序(甚至有不同线程中调用)。

三:回收方法区  

  永久代的垃圾收集主要分为两部分内容:废弃常量和无用的类。

3.1 回收废弃常量

  回收废弃常量与Java堆的回收类似。下面举个栗子说明

  假如一个字符串“abc” 已经进入常量池中,但当前系统没有一个string对象是叫做abc的,也就是说,没有任何string对象的引用指向常量池中的abc常量,也没用其他地方引用这个字面量。如果这是发生内存回收,那么这个常量abc将会被清理出常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

3.2 回收无用的类

  需要同时满足下面3个条件的才能算是无用的类。

  1. 该类所有的实例都已经被回收,也就是Java堆中无任何改类的实例。
  2. 加载该类的ClassLoader已经被回收。
  3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

  虚拟机可以对同时满足这三个条件的类进行回收,但不是必须进行回收的。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制。

----对《深入理解Java虚拟机》第3章垃圾收集器与内存分配策略 3.2小节总结。接下来总结3.3小结垃圾收集算法。

Jvm垃圾回收器(基础篇)的更多相关文章

  1. Jvm垃圾回收器(终结篇)

    知识回顾: 第一篇<Jvm垃圾回收器(基础篇)>主要讲述了判断对象的生死?两种基础判断对象生死的算法.引用计数法.可达性分析算法,方法区的回收.在第二篇<Jvm垃圾回收器(算法篇)& ...

  2. JVM基础系列第9讲:JVM垃圾回收器

    前面文章中,我们介绍了 Java 虚拟机的内存结构,Java 虚拟机的垃圾回收机制,那么这篇文章我们说说具体执行垃圾回收的垃圾回收器. 总的来说,Java 虚拟机的垃圾回收器可以分为四大类别:串行回收 ...

  3. Jvm垃圾回收器(算法篇)

    在<Jvm垃圾回收器(基础篇)>中我们主要学习了判断对象是否存活还是死亡?两种基础的垃圾回收算法:引用计数法.可达性分析算法.以及Java引用的4种分类:强引用.软引用.弱引用.虚引用.和 ...

  4. JVM 垃圾回收器工作原理及使用实例介绍(转载自IBM),直接复制粘贴,需要原文戳链接

    原文 https://www.ibm.com/developerworks/cn/java/j-lo-JVMGarbageCollection/ 再插一个关于线程和进程上下文,待判断 http://b ...

  5. 【转】Java学习---垃圾回收算法与 JVM 垃圾回收器综述

    [原文]https://www.toutiao.com/i6593931841462338062/ 垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的 ...

  6. 垃圾回收算法与 JVM 垃圾回收器综述(转)

    垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的回收方法.不同回收器的实现细节各有不同,但总的来说基本所有的回收器都会关注如下两个方面:找出所有的存 ...

  7. JVM垃圾回收器原理及使用介绍

    JVM垃圾回收器原理及使用介绍 垃圾收集基础 引用计数法(Reference Counting) 标记-清除算法(Mark-Sweep) 复制算法(Copying) 标记-压缩算法(Mark-Comp ...

  8. jvm垃圾回收器介绍

    上篇文章中我们讨论了jvm的内存区域,这篇文章我们来讨论针对的内存区域的垃圾回收机制. 其实针对垃圾回收我们通常考虑三个问题:1.哪些内存需要回收?2.什么时候回收?3.如何回收?下面我们针对这三个问 ...

  9. Hotspot JVM垃圾回收器

    前两篇<JVM入门——运行时数据区><JVM常见垃圾回收算法>所提到的实际上JVM规范以及常用的垃圾回收算法,具体的JVM实现实际上不止一种,有JRockit.J9等待,当然最 ...

  10. JVM垃圾回收器理论分析与详解【纯理论】

    继续上次[https://www.cnblogs.com/webor2006/p/10740084.html]的理论继续..有点吐血的感觉,都不知道学了这么一大堆理论有何实际意义,本身JVM就是个理论 ...

随机推荐

  1. Spring Cloud 微服务笔记(六)Spring Cloud Hystrix

    Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...

  2. selenium3 调用IE Unable to get browser

    本地环境开发,移至服务器上出现Unable to get browser的问题.经过查找找到问题所在(第六点,需要修改注册表增加键): 1.下载IEDriverServer.进入索引页,首先选择版本号 ...

  3. 安装JAVA jdk

      下载软件包,jdk-10.0.1_windows-x64_bin 根据提示一步步安装.安装完成之后,配置环境. 控制面板——>系统——>编辑系统变量 ​ 4. 系统变量 增加path变 ...

  4. DEDECMS织梦文章摘要批量更改方法

    我们建站有时候需要直接把数据库导入,只要修改一下基本的名称信息就可以直接用,但是遇用到一些问题.比如文章摘要不会随着文章内容的更新而更新.织梦(dede)在添加文章的时候会自动生成文章摘要,如果重新修 ...

  5. On the Optimal Approach of Survivable Virtual Network Embedding in Virtualized SDN

    Introduction and related work 云数据中心对于虚拟技术是理想的创新地方. 可生存性虚拟网络映射(surviavable virtual network embedding ...

  6. GDKOI2017滚粗记

    Preface 比赛成绩非常烂,却腐败得非常爽,但是gmh大爷因为和我们腐败,变得更强. 比赛策略有点问题,拼命想正解而没了暴力分 数论题做得比较少,导致只会找规律.知识点需要补充,如AC自动机,启发 ...

  7. react.JS基础

    1.ReactDOM.render() React.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点. <!DOCTYPE html> ...

  8. Android四大组件的简介

    Android开发四大组件分别是: 一.活动(Activity): 用于表现功能.二.服务(Service): 后台运行服务,不提供界面呈现. 三.广播接收器(BroadcastReceiver):用 ...

  9. 远程dump导出svn项目

    使用TortoiseSVN 安装目录下的svnrdump.exe 工具进行导出 1.cmd 到工具路径下 C:\Program Files\TortoiseSVN\bin svnrdump.exe d ...

  10. springboot-项目获取resources下文件碰到的问题(classPath下找不到文件和文件名乱码)

    项目是spring-boot + spring-cloud 并使用maven 管理依赖.在springboot+maven项目下怎么读取resources下的文件实现文件下载? 怎么获取resourc ...