在本专栏的前12篇博客中, 我们主要大致介绍了什么是JVM, 并且详细介绍了class文件的格式。 对于深入理解Java, 或者深入理解运行于JVM上的其他语言, 深入理解class文件格式都是必须的。 如果读者对class文件的格式不是很熟悉, 在阅读本博客下面的文章之前, 建议先读一下前面的12篇博客, 或者参考其他资料, 熟悉class文件的格式。
在深入理解Java虚拟机到底是什么 这篇博客中, 我们有提到过, JVM就是一个特殊的进程, 我们执行的java程序, 都运行在一个JVM进程中, 这个进程的作用就是加载class文件, 并且执行class文件中的代码。 当然, 从一个class文件的加载, 到准备好可执行之前, 还有一段很长的路要走, 以后的文章会详细介绍这个过程。 既然虚拟机作为一个虚拟的计算机, 来执行我们的程序, 那么在执行的过程中, 必然要有地方存放我们的代码(class文件); 在执行的过程中, 总会创建很多对象, 必须有地方存放这些对象; 在执行的过程中, 还需要保存一些执行的状态, 比如, 将要执行哪个方法, 当前方法执行完成之后, 要返回到哪个方法等信息, 所以, 必须有一个地方来保持执行的状态。 上面的描述中, “地方”指的当然就是内存区域, 程序运行起来之后, 就是一个动态的过程, 必须合理的划分内存区域, 来存放各种数据。 所以, 在本文中, 将会详细介绍JVM的运行时数据区。
要理解JVM的运行时数据区, 必须先要理解JVM的体系结构, 因为虚拟机的体系结构基本上解释了“为什么会有这些运行时数据区” 。 在深入理解Java虚拟机到底是什么 这篇文章中也简单的提到过JVM的体系机构, 这里再详细的讲解一下。 JVM的体系结构如下:
由此可见, 运行时数据区的划分, 是和JVM的体系结构相关的。 本文主要介绍运行时数据区的划分, 对体系结构不做深入的讲解。 简单概括一下, 类加载器子系统用于将class文件加载到虚拟机的运行时数据区中(准确的说应该是方法区) 。 可以认为执行引擎是字节码的执行机制, 一个线程可以看做是一个执行引擎的实例。 下面介绍运行时数据区:
类型数据中,除了这些基本信息外, 类型信息还包括以下两个方面:
一个到类的ClassLoader对象的引用
一个到表示该类的Class实例对象的引用
静态变量存储区
由于之前的博客中详细介绍过class文件的格式, 对上面的一些基本信息我们可能比较熟悉, 但是对这两种信息就比较陌生了。 其实说来也简单,每个class都是被一个类加载器加载到方法区的, 类型信息中的到类的ClassLoader对象的引用, 表明了当前的类是被哪个类加载器加载的, 这个信息同时也标示了当前的类型的名称空间。
每当一个class文件被成功的加载到方法区中, JVM总会创建一个Class对象, 来唯一标示这个类。 这个Class对象可以看做是类加载过程的产物, 由于它描述了整个类型信息, 而Java中的反射也是针对的类型信息, 所以这个Class对象是反射的基石, 大多数反射API都是根据Class对象来实现的。
而静态变量也是存在于类型信息中, 可以这么说, 类型信息中, 会有专门的区域存放类的静态变量。 与存在于对象中的实例变量不同, 静态变量存在于类型数据中, 每个类型只有一份,所以也叫类变量。
方法区是一个相对来说比较固定的内存区, 因为它存放的是类型信息, 而类型信息在被加载到方法区中之后, 除了必要的连接和初始化, 一般不会有较大改动,一般情况下, JVM也不会卸载类型信息, 所以方法区也可以称为JVM的静态区。 一个类型的生命周期一般就是整个程序的生命周期。 这也是为什么要慎用静态变量的原因所在, 因为静态变量随类型信息存放在方法区中, 生命周期很长, 如果使用不当, 很容易造成内存泄露。 一个JVM实例中只存在一个方法区, 方法区中的所有类型数据被所有线程共享。
原文地址:http://blog.csdn.net/zhangjg_blog/article/details/24271275