深入理解JVM(四) -- 垃圾内存回收的判定方法和内容
上一篇文章我们学到了对象在内存中是如何存储的已经是如何被访问的,这篇文章将介绍当内存空间不够时,虚拟机将怎样判定对象可不可以被回收已经哪些地方会发生回收。
垃圾回收主要(不是全部)发生在堆内存中,当一个对象没有存在的必要的时候,占着内存明显不行,所以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(四) -- 垃圾内存回收的判定方法和内容的更多相关文章
- 图解JVM垃圾内存回收算法
图解JVM垃圾内存回收算法 这篇文章主要介绍了图解JVM垃圾内存回收算法,由于年轻代堆空间的垃圾回收会很频繁,因此其垃圾回收算法会更加重视回收效率,下面博主和大家来一起学习一下吧 前言 首先,我们要讲 ...
- 推荐收藏系列:一文理解JVM虚拟机(内存、垃圾回收、性能优化)解决面试中遇到问题(图解版)
欢迎一起学习 <提升能力,涨薪可待篇> <面试知识,工作可待篇 > <实战演练,拒绝996篇 > 欢迎关注我博客 也欢迎关注公 众 号[Ccww笔记],原创技术文章 ...
- JVM(四)内存回收(二)
在上一节中"JVM(三)内存回收(一)"我讲到了垃圾回收的几种算法,算是解决了之前提到的3个问题中的最后一个. 关于内存回收,还应该了解常用的内存回收器(GC Collector) ...
- 深入理解JVM一垃圾回收算法
我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. 一.stop the world 在介绍 ...
- JVM(四) 垃圾回收
1. 堆内存结构 Java堆从GC的角度可以细分为:新生代(Eden区.From Survivor区和To Survivor区)和老年代. 1.1 新生代 新生代是用来存放新生的对象.一般占据堆的1/ ...
- 深入理解JVM——关于垃圾回收
关于垃圾回收 仿佛来自上海居委会大妈的灵魂拷问:“你是什么垃圾?” 不 今天我们要说的是JVM的垃圾回收 假如我是一个“人”类的“对象”,也和人的生命一样必有一死,可是“我真的还想再活500年~~”, ...
- 深入理解JVM(五) -- 垃圾回收算法
上篇文章我们了解到哪些内存区域和哪些对象可以被回收,这篇文章我们就来了解一下具体的垃圾回收算法的思路,不讨论具体的实现. 一 最基础算法 标记-清除(Mark-Swap) 为什么说他是最基础的算法,因 ...
- 理解JVM之Java内存区域
Java虚拟机运行时数据区分为以下几个部分: 方法区.虚拟机栈.本地方法栈.堆.程序计数器.如下图所示: 一.程序计数器 程序计数器可看作当前线程所执行的字节码行号指示器,字节码解释器工作时就是通过改 ...
- 深入理解JVM - 1 - Java内存区域划分
作者:梦工厂链接:https://www.jianshu.com/p/7ebbe102c1ae来源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. Java与C++之间有一堵 ...
随机推荐
- 解决WordPress访问中文标签出现404的几个方法
最近很多主题用户提到安装完WordPress后中文标签出现404的情况,出现这种情况一般修改固定链接设置是没有效果的,多数是windows主机带来的麻烦.网上多数人说要修改核心文件class-wp.p ...
- linux学习(1):linux命令大全
Linux命令 目录 1 文件管理... 5 1.1 basename. 5 1.2 cat 5 1.3 cd. 5 1.4 ...
- [转]css3自适应布局单位vw,vh你知道多少?
原文地址:https://www.cnblogs.com/luxiaoxing/p/7544375.html 视口单位(Viewport units) 什么是视口? 在PC端,视口指的是在PC端,指的 ...
- electron---表单验证问题
使用elementui进行表单提交数据的时候,经常会需要用到表单验证的功能,下面就来说说这个功能. <template> <div> <el-form :model=&q ...
- 案例:使用BeautifuSoup4的爬虫
使用BeautifuSoup4解析器,将招聘网页上的招聘单位名称存储出来.其他信息可类似爬取即可 # -*- coding:utf-8 -*- from bs4 import BeautifulSou ...
- matlab中可用于进行轮廓提取的函数
本文主要总结一下在matlab中可用于进行轮廓提取的函数. 1 bwperim 根据参考资料[2]的提示,可以使用bwperim()函数进行轮廓提取,具体代码如下: %读取原图im = imread( ...
- Ehcache 学习入门
目录 介绍 导入jar包 创建配置文件 第一个使用示例 配置文件解析 第一部分:CacheManager 第二部分:diskStore 第三部分:cache 总结 介绍 网上有很多关于Ehcache的 ...
- [LeetCode] 401. Binary Watch 二进制表
A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom ...
- [LeetCode] 549. Binary Tree Longest Consecutive Sequence II 二叉树最长连续序列之 II
Given a binary tree, you need to find the length of Longest Consecutive Path in Binary Tree. Especia ...
- Linq调试实时输出信息扩展方法(摘抄)
原文在此 [译]如何在C#中调试LINQ查询 原linq语句: var res = employees .Where(e => e.Gender == "Male") .Ta ...