上一篇文章我们学到了对象在内存中是如何存储的已经是如何被访问的,这篇文章将介绍当内存空间不够时,虚拟机将怎样判定对象可不可以被回收已经哪些地方会发生回收。

  垃圾回收主要(不是全部)发生在堆内存中,当一个对象没有存在的必要的时候,占着内存明显不行,所以Java内置的GC会对没有必要存在的内存区域进行回收,那么,如何判断一个对象已经没有使用价值了,或者说,已死了呢?

  首先,最直观的方式是在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就+1,当引用值失效时,再-1,任何时刻计数器值为0的对象就是不可能再被使用的,客观的说,这种方式实现简单,判定效率高,在大部分情况下是一个不错的算法,但是它最大的问题在于不能解决对象之间相互引用的问题,例如:objA.instance = objB; objB.instance = objA; 这样两个对象之间互相引用,引用计数器的值都不为0,但是很明显除此之外没有别的地方需要这两个对象,此时使用这种回收机制就显得无能为力。此时,另一种算法:可达性分析,在主流的商用程序语言中,都使用到了这种算法,这种算法的思路是:从一系列定义为GC-Root的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为“引用链”,当一个对象到GC-Root对象没有任何引用链相连时,即无法到达时,认为该对象已经没用了,这种算法很好的解决了上述中提到的对象之间互相引用的问题。

  在Java中,可以作为GC-Roots的对象有以下几种:

  虚拟机栈中引用的对象

  方法区中静态属性引用的对象

  方法区中常量引用的对象

  本地方法栈JNI中引用的对象

  从上文可知,无论是引用计数器和可达性分析(引用链)都与引用这个概念相关,那么什么是引用呢?在JDK1.2以前,引用的定义很直接:如果reference类型数据中存储的是另一块内存的起始地址,就称这块内存存在着一个引用。这种定义很纯粹,但是有些狭隘,它无法描述那些“食之无味,弃之可惜”的对象,我们希望能描述这样一类对象:当内存空间还足够时,可以保留在内存中,如果内存空间在垃圾回收后还是很紧张,则可以抛弃这些对象,很多系统的缓存功能都符合这样的应用场景。于是,在JDK1.2之后,Java定义了四种引用类型:

  1.强引用:在代码中普遍存在,类似"Object a = new Object()"就是强引用,只要强引用存在,垃圾回收器就不会回收被引用的内存。

  2.软引用:Soft Reference,用来描述一些有用但不是必须的对象,当将要发生内存溢出时,会将这些对象列为回收范围进行第二次回收,如果这次回收后还没有足够的可用内存,才会抛出内存溢出。

  3.弱引用:描述的对象与软引用相似,但是比软引用更弱一些,只能生存到下次GC之前,当虚拟机进行内存回收时,无论是否存在软引用,都会对该对象进行回收,在JDK1.2之后,提供了WeakReference来表示弱引用。

  4.虚引用:Phantom Reference,也被称为幽灵引用或幻影引用,是最弱的一种引用关系,他的存在不会对对象的生存时间构成任何影响,也无法通通过虚引用获取一个对象实例,引入它只是为了在被系统回收时得到一个通知。

  tips:当一个对象被可达性算法和引用计数法都判定为“死亡”时,还会进行一次筛选,如果这个类覆盖了Object类的finalize()方法(对于一个对象,这个方法只会调用一次),且可以调用时,会先调用该方法,执行完该方法后如果还是没有满足可存活的条件,才会将其回收,这是文章作者特意提到的,对象可以在该方法中进行“自救”,例如:

  

  将自己this赋值给一个引用,但是只能自救一次,因为该方法只会被调用一次。

  但是作者建议不要使用这种方式拯救对象,因为调用不确定性大,开销大,用finalize()可以做到的,用try-finally可以做的更好,只须了解有这个方法存在即可。

  方法区也是会发生内存回收的

  很多人会认为方法区中不会进行内存回收的操作,虽然在方法区进行内存回收的效率比较低(正常在堆中进行一次GC大约可以释放70%~95%的内存空间),但是还是会执行内存回收,回收的对系那个有两种,一是废弃的常量,二是无用的类。

  1.例如一个常量“abc”已经进入了常量池,但是当前系统没有一个String对象是指向该常量,如果这时候发生了内存回收,并且有必要的话,就会将该常量回收。

  2.判断一个常量是否无用简单,但是判断一个类是否无用比较复杂,需要满足多个条件,首先,该类的所有实例均以被回收,也就是Java堆中不存在该类的实例;其次,该类的ClassLoader已经被回收;并且,该类的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。虚拟机可以对上述类进行回收,但是仅仅是可以,而不是像对象一样,不使用了就必然会回收。

  下一章会介绍虚拟机主要使用的几种垃圾回收算法。

  

深入理解JVM(四) -- 垃圾内存回收的判定方法和内容的更多相关文章

  1. 图解JVM垃圾内存回收算法

    图解JVM垃圾内存回收算法 这篇文章主要介绍了图解JVM垃圾内存回收算法,由于年轻代堆空间的垃圾回收会很频繁,因此其垃圾回收算法会更加重视回收效率,下面博主和大家来一起学习一下吧 前言 首先,我们要讲 ...

  2. 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)

    欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...

  3. JVM(四)内存回收(二)

    在上一节中"JVM(三)内存回收(一)"我讲到了垃圾回收的几种算法,算是解决了之前提到的3个问题中的最后一个. 关于内存回收,还应该了解常用的内存回收器(GC Collector) ...

  4. 深入理解JVM一垃圾回收算法

    我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. 一.stop the world 在介绍 ...

  5. JVM(四) 垃圾回收

    1. 堆内存结构 Java堆从GC的角度可以细分为:新生代(Eden区.From Survivor区和To Survivor区)和老年代. 1.1 新生代 新生代是用来存放新生的对象.一般占据堆的1/ ...

  6. 深入理解JVM——关于垃圾回收

    关于垃圾回收 仿佛来自上海居委会大妈的灵魂拷问:“你是什么垃圾?” 不 今天我们要说的是JVM的垃圾回收 假如我是一个“人”类的“对象”,也和人的生命一样必有一死,可是“我真的还想再活500年~~”, ...

  7. 深入理解JVM(五) -- 垃圾回收算法

    上篇文章我们了解到哪些内存区域和哪些对象可以被回收,这篇文章我们就来了解一下具体的垃圾回收算法的思路,不讨论具体的实现. 一 最基础算法 标记-清除(Mark-Swap) 为什么说他是最基础的算法,因 ...

  8. 理解JVM之Java内存区域

    Java虚拟机运行时数据区分为以下几个部分: 方法区.虚拟机栈.本地方法栈.堆.程序计数器.如下图所示: 一.程序计数器 程序计数器可看作当前线程所执行的字节码行号指示器,字节码解释器工作时就是通过改 ...

  9. 深入理解JVM - 1 - Java内存区域划分

    作者:梦工厂链接:https://www.jianshu.com/p/7ebbe102c1ae来源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. Java与C++之间有一堵 ...

随机推荐

  1. OpenFOAM——具有压差的平行平板间流动(泊肃叶流动)

    本算例翻译整理自:http://the-foam-house5.webnode.es/products/chapter-1-plane-parallel-plates-case/ 这个算例中两平板间没 ...

  2. 用Visual Studio编写UDF的一点小技巧(自动补全宏函数、变量)

    下载Visual Studio,安装VS 下载番茄助手(Visual Assist X),链接:www.wholetomato.com,然后安装番茄助手 打开VS

  3. Mac使用秘钥登录Linux服务器

    简介 在 Mac 上配置 SSH 密钥登录远程的 Linux 相关配置 1.创建本地的 SSH 密钥 本地 生成秘钥对 ssh-keygen -t rsa -C 'youxiang@aliyun.co ...

  4. 008 webpack的其他使用方式

    一:配置 1.配置文件 每次修改main文件,重新打包都要指定入口与出口,比较费事,可以使用配置文件的方式 在根目录下新建webpack.config.js: const path = require ...

  5. Oracle11g R2客户端安装图文详解过程

    转: Oracle11g R2客户端安装图文详解过程 2018-06-17 13:30:26 大话JAVA的那些事 阅读数 4129更多 分类专栏: Oracle   版权声明:本文为博主原创文章,遵 ...

  6. post 发送方式

    /** * post 方式 解码 */ public static String getWebContentByPost(String urlString, String data, final St ...

  7. 深入分析GCC

    深入分析GCC 目录 前言章 GCC概述 11.1 GCC的产生与发展 11.2 GCC的特点 21.3 GCC代码分析 3第2章 GCC源代码分析工具 42.1 vim ctags代码阅读工具 42 ...

  8. nrm -- npm镜像源管理

    nrm nrm(npm registry manager )是npm的镜像源管理工具,有时候国外资源太慢,使用这个就可以快速地在 npm 源间切换 安装nrm 在命令行执行命令,npm install ...

  9. kexue shangwang

    根据实践,pptp.IPsec甚至OpenVPN等kexue上网法已经无法顺利翻越GFW.通过抓包可知,GFW会将pptp的握手期间的ack包吞掉,导致本地一直无法收到服务器端的响应.而OpenVPN ...

  10. 最新 学霸君java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.学霸君等10家互联网公司的校招Offer,因为某些自身原因最终选择了学霸君.6.7月主要是做系统复习.项目复盘.LeetCo ...