Java Virtual Machine

The internal architecture of the Java virtual machine.
上图为JVM框架,图片来源:Inside the Java 2 Virtual Machine 2nd Edition

虽然这Inside the Java 2 Virtual Machine 2nd Edition本书(PDF)是在2000年6月出版的,已经很古老了,但从其给出的JVM结构图来看,JVM整体框架在这15年里几乎没有任何变化。维基百科给出的基于Java SE 7 Edition的JVM框架几乎与这个一模一样。最新消息称JVM已将方法区(Method Area)移除了,将其放在了操作系统层面。单从官方给出的JVM说明文档来看,并未移除该部分的内容,也许消息发布者是针对某一个具体的JVM实现来说的。

抛开年代,就其内容来说,该书主要从设计文档(the abstract specification)、具体实现(a concrete implementation)和运行实例(a runtime instance)三个角度来讲述JVM,并且涉及操作系统、编译等知识,讲得很透彻。

之所以要看JVM相关的东西,主要是听周围的人都在谈论这个东西,所以想一探究竟。我结合自身需求,主要看了本书的第5、8、9、20章,主要浏览了Java虚拟机的框架、类加载器、垃圾回收和线程同步的内容。

Java Virtual Machine

从框架设计来看,JVM总体有5部分内容:

  • 类加载器子系统:启动类加载器(bootstrap)、用户自定义加载器等
  • 运行时数据区
  • 执行引擎:解释执行、即时(Just-In-Time)编译、Java线程模型等
  • 本地方法接口:JNI等
  • 本地方法库

运行时数据区又分为5部分:

  • 方法区(method area):类型信息、常量等
  • 堆(heap):只放对象和数组
  • 栈(Java Stacks):各线程的方法栈等,一般称为Java虚拟机栈
  • 程序计数器(PC registers):各线程的下一条执行语句
  • 本地方法栈(native method stacks):非Java语言方法栈

Method Area V.S. Heap
上图为JVM中方法区与堆区的区别,图片来源:Inside the Java 2 Virtual Machine 2nd Edition

Relations between PC Registers, Java Stacks and Native Method Stacks
上图为JVM中程序计数器、Java虚拟机栈、本地方法栈之间的关系,图片来源:Inside the Java 2 Virtual Machine 2nd Edition

Invoke Java and Native Methods in JVM
上图为JVM中调用Java方法与本地方法之间的区别与联系,图片来源:Inside the Java 2 Virtual Machine 2nd Edition

Garbage Collection

GC Tuning in JVM
图片来源Java SE 6 GC Tuning,未找到Java 7相关的资料,官方只有简单的介绍
垃圾回收是针对堆和方法区来讲的,主要思想是:内存快用完了,清除那些没用的对象吧。回收的算法有很多种,如(以下方法来自Inside the Java 2 Virtual Machine 2nd Edition):

  • 引用计数法
  • 轨迹跟踪法
  • 压缩拷贝法
  • 停止-拷贝法:Thinking in Java中提到的方法,比较流行,缺点是清理时所有线程(除了清理垃圾的GC线程)都得停止运行
  • 自适应法
  • 火车法

不同的JVM实现可能会采用不同的方法,下图是一种流行的停止-拷贝法,对堆区的整理方式分三个层级,详细参阅Java SE 6 GC TuningJava SE 8 GC Tuning

  • Eden Pool是新生代,满了之后将垃圾清空留下来的存入Survivor Pool存活区
  • Survivor Pool是存活区,每次有新的对象进入,原有的存活对象年龄加1,满了之后将年龄超过一定限度的放入Tenured Pool终身存活区。
  • Tenured Pool终身存活区,满了之后运行GC清空无用对象。

需要注意的是方法区虽是永久代,但并不代表不被清理,它只是相对堆区更为稳定而已,满了之后同样由GC线程清理。

A Popular GC Implementation
上图为一种流行的GC实现方式,图片来源Java虚拟机:基本指南

同步与协作

JVM中堆和方法区被所有线程共享的,为保证数据同步和多线程之间的协作,JVM提供了一种机制叫做monitor。
对象锁:JVM中monitor的实际实现形式,就是对象锁,JVM中的锁都是对象锁。
类锁:实际上是以对象锁的形式实现的,因为JVM在加载一个类文件时会创建一个java.lang.Class实例,对一个类加锁时,实际上是对那个类的Class实例对象加锁。

监控JVM

Anturis Console-JVM monitoring

评论