用空间换时间 —— Java虚拟机的算法实现

原创 2017年08月13日 16:36:46

带着问题阅读

  • 垃圾回收时,需不需要暂停掉除GC线程外的其他线程?
  • 内存那么大,HotSpot如何快速地找到对象?


导语

上一讲介绍了虚拟机是如何利用可达性算法,判断一个对象是否需要回收,而HotSpot在实现这个算法时,必须对算法的执行效率有严格的要求,才能保证虚拟机的高效运行,那么,HotSpot是如何实现的呢?

本文是Effective Java专栏Java虚拟机专题的第五讲,如果你觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给你身边的工程师同学。

在学习本节课程之前,建议您了解一下以下知识点:


快速找出GC Roots

可达性分析算法需要先找到GC Roots(什么是GC Roots),而如何在那么大的内存中找到适合当GC Roots的对象呢?如果每次GC都需要遍历全部内存,必然会消耗很多时间。

而要知道,在GC期间,GC线程以外的其他线程必须被冻结,不可以出现GC过程对象引用关系还在不断发生变化的情况,因此在GC进行时,必须暂停所有的Java执行线程(Sun称之为“Stop The World”)。所以,虚拟机必须尽量的优化GC过程的效率,减少暂停的时间。那么对于GC Roots,HotSpot是如何快速确定的呢?

这时候,准确式GC的作用就体现出来了,它采用一组称为OopMap的数据结构,来保存对象引用的位置,因此在GC时,虚拟机不必在茫茫内存大海中查找引用,只需要拿着OopMap这本字典,就可以快速地查找到所有的引用,并确定GC Roots了(典型的用空间换时间的做法)。



安全点

通过OopMap,HotSpot可以很快完成GC Roots的查找,但是,如果在每一行代码都有可能发生GC,那么也就意味着得为每一行代码的指令都生成OopMap,这样将占用大量的空间。实际上,HotSpot也不会这么做。

HotSpot只在特定的位置记录了OopMap,这些位置就叫做安全点(Safepoint),也就是说,程序并非在任意地方都可以停下了进行GC,只有到达了安全点之后才能进行。安全点一般在这些指令上产生:方法调用、循环跳转、异常跳转等。

当GC发生时,虚拟机会将中断标志设置为true,各个线程在执行时,到达安全点后,就会主动去轮询这个标志,发现中断标志为true时,就主动中断挂起;否则,则继续执行。


安全区域

前面提到的安全点,是在线程正常执行的前提才才有效的,假如线程处于sleep或者blocked状态,就无法走到安全点去中断挂起,而JVM显然不可能等待线程恢复正常,这个时候,就需要安全区域(Safe Region)来解决。

安全区域是指在一段代码片段内,引用关系不会发生变化,在这段区域内,任意地方开始GC都是安全的

当线程进入Safe Region时,首先标识自己已经进入Safe Region,这样,当HotSpot发起GC时,就不需要管这些安全区域内的线程了;当线程要离开Safe Region时,会检查系统是否已经完成了GC(有些垃圾回收器可能只需要检查是否完成了GC Roots查找),如果完成,则线程继续进行,否则就继续等待,直到受到可以安全离开Safe Region的信号。


总结

这一讲介绍了HotSpot在实现可达性分析算法时的算法,讲解了OopMap、安全点和安全区域等概念,通过这两讲的讲解,你已经知道了,垃圾回收是如何发起的,那么发起之后,又是如何回收的呢?这是接下来要讲的内容。


上一节课后思考题的答案

上一讲的问题是——“GC开始后,是否需要暂停除GC线程以外的其他线程?为什么?

答案在本讲中已经提到了,在GC期间,GC线程以外的其他线程必须被冻结,不可以出现GC过程对象引用关系还在不断发生变化的情况,因此在GC进行时,必须暂停所有的Java执行线程(Sun称之为“Stop The World”)

试想一下,假如GC期间其他线程不暂停,那么对于这两行代码:

obj = null;

obj = new Object();

obj.dosomething();

假如在代码执行到第一行时,GC线程进行了标记,将obj标记为需要回收,然而此时其他线程没有暂中断,继续执行第二行代码,执行完之后,GC遍历待回收的对象,将obj回收,接下来要发生的事情想必大家都很熟悉了——NullPointerException.


参考资料

  • 《深入理解Java虚拟机》 周志明


版权声明:本文为博主原创文章,未经博主允许不得转载。

关于时间空间转换在java编程中的使用

如题:如果对于计算机而言所有的
  • wnm23
  • wnm23
  • 2014年06月14日 20:30
  • 811

各种排序算法的java实现及时间、空间复杂度、稳定程度总结

最近闲着没事,就随便看了看数据结构,看到各种排序算法时,突然心血来潮,就想,以前都是用C++实现的,能不能用java实现所有的排序算法呢?而且顺便练习一下递归的使用(因为我最不擅长使用的就是递归) ...
  • nkliming
  • nkliming
  • 2012年06月16日 11:29
  • 6854

HDU1397(以空间换取时间)

题目的大致意思是对于任何一个大于等于4的偶数n,至少存在一对素数p1,p2。使得n=p1+p2,给定一个偶数n,可以分解几对素数之和。n的取值范围为4-32767。 #include int is...
  • mxway
  • mxway
  • 2013年02月06日 19:04
  • 1144

算法设计与分析-时间和空间的权衡

引入问题: 考虑一个计算函数值的问题:   你可以完全不用任何计算方法,先把函数值计算好(例如计算三角函数的值的那张表),把这些预先就计算好了的值存储于计算机中,当你需要这个函数值时,直 接去取...
  • mengzhejin
  • mengzhejin
  • 2014年07月16日 13:26
  • 1685

Linux虚拟内存与交换空间机制

对于一台x86(32bit)的操作系统来说,假设它有2G的物理内存,物理内存分成以许多个4k为单位大小的页框,这些页框就是存储进程的最小单位: 为了解决系统运行过程中不同进程之间内存的合理分配和...
  • u014753393
  • u014753393
  • 2015年12月06日 18:37
  • 1223

《深入理解java虚拟机》学习笔记3——垃圾回收算法

Java虚拟机的内存区域中,程序计数器、虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭;栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构...
  • qq_23211905
  • qq_23211905
  • 2017年05月21日 21:12
  • 172

《深入理解java虚拟机》学习笔记3——垃圾回收算法

原文出处:http://blog.csdn.net/chjttony/article/details/7883068 Java虚拟机的内存区域中,程序计数器、虚拟机栈和本地方法栈三个区域是线程私有的,...
  • qq_24028753
  • qq_24028753
  • 2017年07月18日 09:21
  • 308

常用垃圾收集算法——《深入理解Java虚拟机》笔记

概述垃圾收集器(Garbage Collection, GC)的历史要比Java久远,且并非Java独有,GC主要完成以下三件事情: 哪些内存需要回收 什么时候回收 如何回收 对于Java内存运行时区...
  • u014738140
  • u014738140
  • 2016年08月28日 22:17
  • 573

深入学习Java虚拟机之——垃圾收集算法与垃圾收集器

今天我们将一起学习Java虚拟机使用垃圾收集算法和常见的垃圾收集器。Java虚拟机内存区域的程序计数器、虚拟机栈和本地方法栈3个区域是随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出出栈和入栈。...
  • jcncsdn
  • jcncsdn
  • 2016年05月06日 11:36
  • 553

《深入理解java虚拟机》学习笔记3——垃圾回收算法

Java虚拟机的内存区域中,程序计数器、虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭;栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构...
  • wangjun_818
  • wangjun_818
  • 2017年06月27日 16:14
  • 248
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用空间换时间 —— Java虚拟机的算法实现
举报原因:
原因补充:

(最多只允许输入30个字)