1.  前言

  这一版块内容比较多,分为两篇文章来做笔记。本文讲述上半部分垃圾收集部分;下一篇文章写内存分配部分。

2.  垃圾收集器与内存分配策略

2.1  概述

  对于垃圾回收机制(Garbage Collection,GC),需要思考以下三个问题:

  1. 哪些内存需要回收?
  2. 什么时候回收?
  3. 如何回收?

2.2  对象已死吗?

  堆里面存放着Java中几乎所有的对象实例,垃圾收集器在对堆进行回收前,首先要做的当然是判断哪些对象是“活的,哪些对象是“死的“?

2.1.1 引用技术算法

  主流的java虚拟机不是通过引用技术器算法来管理内存的,其主要的原因在于:难以解决对象的相互循环的问题(通过计数器值为0,判断对象为不能再使用对象,进而回收掉)。下面java代码示例,可以测试说明引用计数器的缺陷:

/*
* main()方法执行之后,objA和objB会不会被GC回收
*/ public class ReferenceCountingGC { public Object instance = null;
private static final int _1MB =1024 * 1024; /*
*这个成员属性的唯一意义就是占一点内存,以便于能够在GC
*的日志之中看清楚是否被回收过?
*/
private byte[] bigSize = new byte[2 * _1MB];
public static void main(String[] args){
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA = null;
objB = null;
// 假设在这行发生GC,那么objA和objB能否被回收?
System.gc();
}
}

  运行结果显示如下:

  通过上述代码,运行后,在GC日志中包含“5812k---->379k”,意味着虚拟机并没有因为这两个对象相互引用就不回收它们,这也从侧面反应了虚拟机并不是通过引用计数算法来判断对象是否存活的。

2.1.2  可达性分析算法

  在java语言中,java虚拟机(JVM)就是通过可达性分析算法来完成对象的回收的。这个算法的思路是,通过一系列的“GC Roots”的对象作为起始点,从这些节点开始往下搜索,搜索所走过的路径称为引用链路(Reference Chain),当一个对象到GC Roots没有任何引用链相连接时(用图论的话来说,就是从GC Roots到这个对象不可达到),则证明此对象是不可用的,需要进行回收。下面用图示例说明:

  如上图所示,对象1~4与GC Roots相关联,是可达的,判定是仍热存活的对象。而对象5~7,虽然相互间有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。

  在java语言中,可作为GC Roots的对象包括以下几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  2. 方法区中静态属性引用的对象;
  3. 方法区中常量引用的对象;
  4. 本地方法栈中JNI(一般说的Native方法)引用的对象。

2.1.3  再谈引用

  在JDK1.2之前,Java对引用定义很传统:如果引用(reference)类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。在JDK1.2之后,java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用这4种,引用强度依次逐渐减弱

  1. 强引用(Strong Reference):类似"Object obj = new Object()"的这类引用,只要强引用还存在,垃圾收集器将永远不会回收掉被引用的对象。
  2. 软引用(Soft Reference):用来描述一些有用但并非必需的对象。系统发生内存溢出之前,将会把这些对象列进回收范围之中进行第二次回收。如果回收过后仍然没有足够的内存,才会抛出内存溢出异常。JDK1.2之后,提供了SoftReference类来实现软引用。
  3. 弱引用(Weak Reference):也是用来描述非必需的对象。当垃圾收集器工作时,无论内存是否足够,都会回收掉只被弱引用关联的对象。提供了WeakReference类来实现弱引用。
  4. 虚引用(Phantom Reference):最弱的一种引用方式,对象虚引用的存在不会对对象的生存时间构成影响,也无法通过虚引用取得一个对象实例。设置虚引用的唯一作用在于,对象被垃圾收集回收时可以收到一个系统通知。提供了PhantomReference类来实现虚引用。

2.1.4  两次标记

  即使是可达性分析算法中的不可达对象,要宣告“死亡”至少仍需要经历两次的标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且再进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行了”,将会被回收。第一次标记后对象会被放置在F-Queue的队列中,如果对象想在finalize()方法中成功拯救自己,只要重新与引用链(GC Roots链)的任何一个对象建立关联即可。下面代码演示一个对象的自我拯救过程:

/*
* 以下代码演示说明两点:
* 1.对象可以在被GC时完成自我拯救;
* 2.这种自我拯救的机会只有一次,因为一个对象的finalize方法只能被系统调用一次
*/ public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive(){
System.out.println("yes,i am still alive");
} @Override
protected void finalize() throws Throwable{
super.finalize();
System.out.println("finalize method executed!!!");
FinalizeEscapeGC.SAVE_HOOK = this;
} public static void main(String[] args) throws Throwable{
SAVE_HOOK = new FinalizeEscapeGC();

// 对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
// 因为finalize方法优先级很低,所以暂停0.5s等它
Thread.sleep(500);
if (SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else {
System.out.println("no,i am dead");
} // 下面这段代码完全相同,却自救失败了
SAVE_HOOK = null;
System.gc();
// 因为finalize方法优先级很低,所以暂停0.5s等它
Thread.sleep(500);
if (SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else {
System.out.println("no,i am dead");
}
}
}

  程序运行的结果如下所示:

  从运行结果中可以看出,SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集之前成功逃走了。但是,两段一样的代码,后者却被回收了,这就说明了finalize()方法只能被系统自动调用一次,如果对象面临再一次回收,finalize()方法不会再次执行

2.1.5  回收方法区

  方法区的垃圾收集器(或者HotSpot虚拟机永久代的垃圾收集器)主要收集两部分内容:废弃常量、无用的类。但是,在方法区进行垃圾回收的效率远远低于在堆中垃圾收集的效率。

(1)  废弃常量的回收:一个常量进入常量池中,假如当前系统没有任何一个对象引用该常量,将会发生内存回收;

(2)  无用的类的回收:满足以下三个条件的类才能算是“无用的类”:

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

  满足以上3个条件只是可以进行类的回收。但是,是否进行回收还取决于虚拟机中设定的一些参数来控制。

深入理解java虚拟机_第三章(上)----->垃圾收集器与内存分配策略的更多相关文章

  1. 《深入理解Java虚拟机》之(二、垃圾收集器与内存分配策略)

    程序计数器.虚拟机栈.本地方法栈3个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟着回收了,而java堆和方法区 ...

  2. 深入理解Java虚拟机学习笔记(二)-----垃圾收集器与内存分配策略

    写在前面 本节常见面试题: 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好处). 如何判断一个常量是废弃常量 如何 ...

  3. 《深入理解Java虚拟机》笔记--第三章 、垃圾收集器与内存分配策略

    1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言. Java的垃圾收集(Garbage Collection)主要关注堆和方法区的内存回收. 在GC堆进行回收前,第一件 ...

  4. 深入JAVA虚拟机笔记-垃圾收集器与内存分配策略

    第三章:垃圾收集器与内存分配 问题:1.哪些内存需要回收 2.什么时候回收 3.怎么回收 回收方法区:

  5. 《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略

    第三章 垃圾收集器与内存分配策略 3.1 概述 哪些内存需要回收 何时回收 如何回收 程序计数器.虚拟机栈.本地方法栈3个区域随线程而生灭. java堆和方法区的内存需要回收.   3.2 对象已死吗 ...

  6. 《深入理解Java虚拟机》(三)垃圾收集器与内存分配策略

    垃圾收集器与内存分配策略 详解 3.1 概述 本文参考的是周志明的 <深入理解Java虚拟机>第三章 ,为了整理思路,简单记录一下,方便后期查阅. 3.2 对象已死吗 在垃圾收集器进行回收 ...

  7. Java虚拟机垃圾回收(三) 7种垃圾收集器

    Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理 在<Java虚拟机垃圾回收(一) 基础>中了解到如何判断对象是存活还是已经死亡?在<Java ...

  8. 深入理解java虚拟机----->垃圾收集器与内存分配策略(下)

    1.  前言 内存分配与回收策略 JVM堆的结构分析(新生代.老年代.永久代) 对象优先在Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保  2.  垃圾 ...

  9. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

随机推荐

  1. 写给想成为前端工程师的同学们  ―前端工程师是做什么的?a

    前端工程师是做什么的? 前端工程师是互联网时代软件产品研发中不可缺少的一种专业研发角色.从狭义上讲,前端工程师使用 HTML.CSS.JavaScript 等专业技能和工具将产品UI设计稿实现成网站产 ...

  2. Ionic3 启动页以及应用图标

    将新的启动页和应用图标图片(最好是高清png)上传到根目录 resources 使用命令自动生成,通过CMD进入项目所在文件夹,分别执行 ionic cordova resources android ...

  3. OR in Matrix

    OR in Matrix Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submi ...

  4. 编译安装PHP 时遇到问题解决方法.

    编译安装PHP时出现下面的错误代码: error 2 checking for pkg-config... /usr/bin/pkg-config configure: error: Cannot f ...

  5. HTML5与phonegap接口对比

    HTML5与phonegap接口对比 接口 HTML5 phonegap 差异 地理定位 geolocation 单次定位: navigator.geolocation.getCurrentPosit ...

  6. 讨论.NET Core 配置对GC 工作模式与内存的影响

    引出问题: Asp.net core应用在 Kubernetes上内存使用率过高问题分析 https://mp.weixin.qq.com/s/PqhUzvFpzopU7rVRgdy7eg 这篇文章中 ...

  7. TweenMax动画库学习

    之前在做HTML5移动端开发的时候,用的都是Animate.css,这个插件封装的的确很好,但是在做一些缓动方面的动画,它也有一定的不足之处,比如手要写一个连续的动画,需要不停的去重复写函数,使得代码 ...

  8. HTML5技术分享 ES2017继发与并发

    大家都知道,async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了.你可以用then方法指定下一步的操作. 进一步说,async函数完 ...

  9. [转]the service mysql57 failed the most recent status[/br]mysql57 was not found解决办法

    转自:http://forums.mysql.com/read.php?169,622722,622877#msg-622877 安装完mysql5.7.12后想要stop或者restart都会出现以 ...

  10. 老男孩Python全栈开发(92天全)视频教程 自学笔记04

    day4课程目录: 逻辑运算符 while循环 day4课程内容梳理: 逻辑运算符 算数运算符:+,-,*,/,%,** 比较运算符:< ,>, ==,<=,>=,!=, 逻辑 ...