1、Java虚拟机的定义

Java虚拟机(Java Virtual Machine),简称JVM。当我们说起Java虚拟机时,可能指的是如下三种不同的东西:

  • 抽象的虚拟机规范
  • 规范的具体实现
  • 一个运行中的虚拟机实例

Java虚拟机抽象规范仅仅是一个概念,在《The Java Virtual Machine Specification》中有详细的描述。

该规范的实现,可能来自多个提供商,并存在于多个平台上,它或者是全部由软件实现,或者是以硬件和软件相结合的方式来实现。JVM的实现有很多,广为使用的主要有三个(由于Sun和BEA被Oracle收购,HotSpot、JRockit已都为Oracle的):

  • Sun HotSpot(服务端、桌面、嵌入式 通用)
  • BEA JRockit(专注于服务端)
  • IBM J9 VM(服务端、桌面、嵌入式 通用)

当运行一个Java程序的时候,也就在运行一个Java虚拟机实例。注意,我们所说的Java平台无关性是指class文件的平台无关性,JVM是和平台相关的,不同操作系统对应不同的JVM。

2、JVM架构

HotSpot虚拟机是官方的、最常用的JVM规范实现,这里以HotSpot虚拟机为例。

2.1、HotSpot JVM架构

如图,JVM可以分为三部分:类加载子系统、运行时数据区、执行引擎。

(图片来源:Java Garbage Collection Introduction

更详细的结构:

(图片来源:The JVM Architecture Explained

2.2、HotSpot JVM在Java SE中的位置

(图片来源:Jave SE Platform at a Glance

3、JVM运行时数据区

JVM规范定义了若干种程序运行时使用到的运行时数据区

  1. 有一些是  随虚拟机的启动而创建,随虚拟机的退出而销毁
  2. 第二种则是与线程一一对应,随线程的开始和结束而创建和销毁

java虚拟机所管理的内存将会包括以下几个运行时数据区域:

3.1、程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器。

每一条JVM线程都有自己的PC寄存器

在任意时刻,一条JVM线程只会执行一个方法的代码。该方法称为该线程的当前方法(Current Method)

如果该方法是java方法,那PC寄存器保存JVM正在执行的字节码指令的地址

如果该方法是native,那PC寄存器的值是undefined。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

3.2、Java虚拟机栈

即线程运行栈,与PC寄存器一样,java虚拟机栈(Java Virtual Machine Stack)也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。

虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

JVM stack 可以被实现成固定大小,也可以根据计算动态扩展。

如果采用固定大小的JVM stack设计,那么每一条线程的JVM Stack容量应该在线程创建时独立地选定。JVM实现应该提供调节JVM Stack初始容量的手段。

如果采用动态扩展和收缩的JVM Stack方式,应该提供调节最大、最小容量的手段。

JVM Stack 异常情况:

StackOverflowError:当线程请求分配的栈容量超过JVM允许的最大容量时抛出

OutOfMemoryError:如果JVM Stack可以动态扩展,但是在尝试扩展时无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈时抛出。

3.3、本地方法栈

Java虚拟机可能会使用到传统的栈来支持native方法(使用Java语言以外的其它语言编写的方法)的执行,这个栈就是本地方法栈(Native Method Stack)

如果JVM不支持native方法,也不依赖与传统方法栈的话,可以无需支持本地方法栈。

如果支持本地方法栈,则这个栈一般会在线程创建的时候按线程分配。

异常情况:

StackOverflowError:如果线程请求分配的栈容量超过本地方法栈允许的最大容量时抛出

OutOfMemoryError:如果本地方法栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的本地方法栈,那Java虚拟机将会抛出一个OutOfMemoryError异常。

3.4、方法区

方法区(Method Area)是可供各条线程共享的运行时内存区域。存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法

方法区在虚拟机启动的时候创建。

方法区的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。

方法区在实际内存空间中可以是不连续的。

Java虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段,对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段。

Java 方法区异常:

OutOfMemoryError: 如果方法区的内存空间不能满足内存分配请求,那Java虚拟机将抛出一个OutOfMemoryError异常。

注:

方法区常被称为持久代(Permanent Generation),主要存放的是Java类定义信息,与垃圾收集器要收集的Java对象关系不大。(“持久代”概念针对HotSpot虚拟机而言,BEA JRockit、IBM J9等不存在此概念,且在HotSpot中将逐渐放弃永久代并改为采用Native Memory来实现方法区。JDK1.7开始逐步“去永久代”)

运行时常量池

运行时常量池(Runtime Constant Pool)是每一个类或接口的常量池(Constant_Pool)的运行时表现形式,它包括了若干种常量:编译器可知的数值字面量到必须运行期解析后才能获得的方法或字段的引用。

运行时常量池是方法区的一部分。每一个运行时常量池都分配在JVM的方法区中,在类和接口被加载到JVM后,对应的运行时常量池就被创建。

在创建类和接口的运行时常量池时,可能会遇到的异常:

OutOfMemoryError:当创建类和接口时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大内存空间后就会抛出OutOfMemoryError

3.5、Java堆

在JVM中,堆(heap)是可供各条线程共享的运行时内存区域,也是供所有类实例和数据对象分配内存的区域。

Java堆载虚拟机启动的时候就被创建,堆中储存了各种对象,这些对象被自动管理内存系统(Automatic Storage Management System,也即是常说的“Garbage Collector(垃圾回收器)”)所管理。这些对象无需、也无法显示地被销毁。

Java堆的容量可以是固定大小,也可以随着需求动态扩展,并在不需要过多空间时自动收缩。

Java堆所使用的内存不需要保证是物理连续的,只要逻辑上是连续的即可。

JVM实现应当提供给程序员调节Java 堆初始容量的手段,对于可动态扩展和收缩的堆来说,则应当提供调节其最大和最小容量的手段。

Java 堆异常:

OutOfMemoryError:如果实际所需的堆超过了自动内存管理系统能提供的最大容量时抛出。

注:

方法区/永久代/元空间

方法区常又被称为永久代(PermGen space)、元空间(Metaspace),它们的区别是:方法区为JVM的规范,永久代、元空间分别是方法区在HotSpot中的一种实现,对于其他类型的虚拟机实现,如 JRockit(BEA)、J9(IBM),其并没有永久代、元空间这些概念。

  • 从JDK1.7开始,逐渐开始去永久代工作:JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。(如符号引用(Symbols)转移到了native heap;字面量(interned strings)、类的静态变量(class statics)转移到了java heap);
  • 从JDK1.8起,采用元空间代替永久代。元空间与永久代的区别是,元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

4、参考资料

[1]http://chenzhou123520.iteye.com/blog/1585224,(其即参考自《深入理解Java虚拟机——JVM高级特性与最佳实践》)

Java虚拟机及运行时数据区的更多相关文章

  1. Java虚拟机一 运行时数据区(栈、堆、方法区等)

    Java虚拟机的内存管理主要分两点:内存分配以及内存回收.· 一.内存分配图: 注: 所占区域的大小与实际的内存大小比例并无直接关系. 解读: 1.如图,分成两种颜色的内存区域,其中蓝色的是线程隔离的 ...

  2. 【Java虚拟机】运行时数据区

    Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随 ...

  3. 深入理解Java虚拟机(一) 运行时数据区划分

    前言:从我学Java的第一天开始,我的大学老师就告诉我 Java语言相比C.C++的语言有一个非常强大的功能,那就是自动内存管理:我们用Java编码时不需要申请或释放内存等,这些工作全部交由我们的Ja ...

  4. java虚拟机规范-运行时数据区

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 数据类型 java总共有两种数据类型:基本类型和引用类型.java虚拟机 ...

  5. Java虚拟机_运行时数据区

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途.各自的创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程启动 ...

  6. java内存区域----运行时数据区

    Java虚拟机的内存区域也叫做java运行时数据区,共分为五个部分:程序计数器,方法区,本地方法栈,虚拟机栈和堆.方法区和堆是线程之间所共有的,程序计数器,本地方法栈,虚拟机栈是线程私有的.其中虚拟机 ...

  7. 深入理解Java虚拟机-JVM运行时数据区域

    一.运行时数据区域 1.程序计数器 程序计数器( Program Counter Register) 是一块较小的内存空间, 它可以看作是当前线程所执行的字节码的行号指示器. Java虚拟机的多线程是 ...

  8. 【JVM】虚拟机初见-运行时数据区图解

    本文是听咕泡XX公开课视频整理的笔记,较书本更为总结,感谢. 计算机模型(汇编知识):数据集(数据).指令集(操作指令,+-等).控制集(分支循环) JVM运行时的数据区: 程序计数器(每个线程都有) ...

  9. java虚拟机规范-运行时栈帧

    前言 java虚拟机是java跨平台的基石,本文的描述以jdk7.0为准,其他版本可能会有一些微调. 引用 java虚拟机规范 java虚拟机规范-运行时数据区 java内存运行时的栈帧结构 java ...

随机推荐

  1. java实现敏感词过滤(DFA算法)

    小Alan在最近的开发中遇到了敏感词过滤,便去网上查阅了很多敏感词过滤的资料,在这里也和大家分享一下自己的理解. 敏感词过滤应该是不用给大家过多的解释吧?讲白了就是你在项目中输入某些字(比如输入xxo ...

  2. linux memcached安装

    准备安装包: libevent-2.0.21-stable.tar.gz  //Memcached服务端的依赖包 memcached-1.4.29.tar.gz   //Memcached服务端 li ...

  3. Nginx 访问日志轮询切割

    Nginx 访问日志轮询切割脚本 #!/bin/sh Dateformat=`date +%Y%m%d` Basedir="/application/nginx" Nginxlog ...

  4. mkdir,rmdir,cp,rm,mv,cat,touch用法

    一.mkdir新建目录 1.进入tmp目录,查看该目录下面的子目录 [root@localhost ~]# cd /tmp[root@localhost tmp]# lshsperfdata_root ...

  5. 在使用EF时调用DBFUNCTION扩展方法时,发生ENTITYCOMMANDEXECUTIONEXCEPTION 异常的解决办法

    System.Data.Entity.Core.EntityCommandExecutionException : An error occurred while executing the comm ...

  6. 四种比较简单的图像显著性区域特征提取方法原理及实现-----> AC/HC/LC/FT。

    laviewpbt  2014.8.4 编辑 Email:laviewpbt@sina.com   QQ:33184777 最近闲来蛋痛,看了一些显著性检测的文章,只是简单的看看,并没有深入的研究,以 ...

  7. 【原】移动web滑屏框架分享

    本月26号参加webrebuild深圳站,会上听了彪叔的对初心的讲解,“工匠精神”这个词又一次被提出,也再次引起了我对它的思考.专注一个项目并把它做得好,很好,更好...现实工作中,忙忙碌碌,抱着完成 ...

  8. 例解 Linux cd 命令

    cd 命令是 *nix 系统中最基本的命令,它所做的事情是改变你当前所在的目录.本文详细介绍该命令,它所能完成的功能以及关于该命令内在的东西. cd 命令:一个内置命令 BASH Shell 是大多 ...

  9. Ioc和Ao使用扩展

    一.Bean作用域 spring容器创建的时候,会将所有配置的bean对象创建出来,默认bean都是单例的.代码通过getBean()方法从容器获取指定的bean实例,容器首先会调用Bean类的无参构 ...

  10. [bzoj2653][middle] (二分 + 主席树)

    Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b ...