导读:详细而深入的总结,是对知识“豁然开朗”之后的“刻骨铭心”,想忘记都难。

  Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我们对jvm有了大体的认识,进入本文之后我们将具体而详细的介绍jvm的方方面面,而本文主要讲的是jvm的组成,了解了它,就揭开了jvm的神秘面纱。

  一、jvm的主要组成部分

  类加载器(ClassLoader)

  运行时数据区(Runtime Data Area)

  执行引擎(Execution Engine)

  本地库接口(Native Interface)接下来我们来看以上4个主要组成部分的用途。

  二、jvm组成部分的用途

  程序在执行之前先要把java代码转换成字节码(class文件),jvm首先需要把字节码通过一定的方式类加载器(ClassLoader)把文件加载到内存中运行时数据区(Runtime Data Area),而字节码文件是jvm的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine)将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口本地库接口(Native Interface)来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。

  而我们通常所说的jvm组成指的是运行时数据区(Runtime Data Area),因为通常需要程序员调试分析的区域就是“运行时数据区”,或者更具体的来说就是“运行时数据区”里面的Heap(堆)模块,那接下来我们来看运行时数据区(Runtime Data Area)是由哪些模块组成的。

  三、运行时数据区

  jvm的运行时数据区,不同虚拟机实现可能略微有所不同,但都会遵从Java虚拟机规范,Java 8 虚拟机规范规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

  程序计数器(Program Counter Register)

  Java虚拟机栈(Java Virtual Machine Stacks)

  本地方法栈(Native Method Stack)

  Java堆(Java Heap)

  方法区(Methed Area)接下来我们分别介绍每个区域的用途。

  3.1 程序计数器

  程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解析器的工作是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

  特性:内存私有

  由于jvm的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,也就是任何时刻,一个处理器(或者说一个内核)都只会执行一条线程中的指令。因此为了线程切换后能恢复到正确的执行位置,每个线程都有独立的程序计数器。

  异常规定:无

  如果线程正在执行Java中的方法,程序计数器记录的就是正在执行虚拟机字节码指令的地址,如果是Native方法,这个计数器就为空(undefined),因此该内存区域是唯一一个在Java虚拟机规范中没有规定OutOfMemoryError的区域。

  3.2 Java虚拟机栈

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

  特性:内存私有,它的生命周期和线程相同。

  异常规定:StackOverflowError、OutOfMemoryError

  1、如果线程请求的栈深度大于虚拟机所允许的栈深度就会抛出StackOverflowError异常。

  2、如果虚拟机是可以动态扩展的,如果扩展时无法申请到足够的内存就会抛出OutOfMemoryError异常。

  3.3 本地方法栈

  本地方法栈(Native Method Stack)与虚拟机栈的作用是一样的,只不过虚拟机栈是服务Java方法的,而本地方法栈是为虚拟机调用Native方法服务的。

  在Java虚拟机规范中对于本地方法栈没有特殊的要求,虚拟机可以自由的实现它,因此在Sun HotSpot虚拟机直接把本地方法栈和虚拟机栈合二为一了。

  特性和异常:同虚拟机栈,请参考3.2的知识点。

  3.4 Java堆

  Java堆(Java Heap)是Java虚拟机中内存最大的一块,是被所有线程共享的,在虚拟机启动时候创建,Java堆唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配、标量替换优化的技术将会导致一些微妙的变化,所有的对象都分配在堆上渐渐变得不那么“绝对”了。

  特性:内存共享

  异常规定:OutOfMemoryError

  如果在堆中没有内存完成实例分配,并且堆不可以再扩展时,将会抛出OutOfMemoryError。

  Java虚拟机规范规定,Java堆可以处在物理上不连续的内存空间中,只要逻辑上连续即可,就像我们的磁盘空间一样。在实现上也可以是固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是可扩展的,通过-Xmx和-Xms控制。

  3.5 方法区

  方法区(Methed Area)用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。

  误区:方法区不等于永生代

  很多人原因把方法区称作“永久代”(Permanent Generation),本质上两者并不等价,只是HotSpot虚拟机垃圾回收器团队把GC分代收集扩展到了方法区,或者说是用来永久代来实现方法区而已,这样能省去专门为方法区编写内存管理的代码,但是在Jdk8也移除了“永久代”,使用Native Memory来实现方法区。

  特性:内存共享

  异常规定:OutOfMemoryError

  当方法无法满足内存分配需求时会抛出OutOfMemoryError异常。

  四、扩展知识

  本节将扩展一些和内存分配有关的知识。

  4.1 运行时常量池

  运行时常量池是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table)用于存放编译期生成的各种字面量和符号引用,这部分在类加载后进入方法区的运行是常量池中,如String类的intern()方法。

  4.2 直接内存

  直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,但这部分内存也会被频繁的使用,而且可能导致OutOfMemoryError。在JDK 1.4中新加入了NIO类,引入了一种基于Channel与缓冲区Buffer的IO方式,它通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用操作,它因此更高效,它避免了Java堆和Native堆来回交换数据的时间。

  注意:直接内存分配不会受到Java堆大小的限制,但是受到本机总内存大小限制,在设置虚拟机参数的时候,不能忽略直接内存,把实际内存设置为-Xmx,使得内存区域的总和大于物理内存的限制,从而导致动态扩展时出现OutOfMemoryError异常。

  五、总结

  本文讲了jvm的主要组成部分,以及组成部分中最重要的运行时数据区(Runtime Data Area)的构成,其中程序计数器、虚拟机栈和本地方法为私有内存,会随着线程而生,随着线程而灭,而Java堆作为最大的内存区域将是开发人员重点关注的内存区域,还有方法区以及运行时常量区与永生代的关系,最后讲了直接内存的实现过程已经使用时需要主要的点,希望能够帮助大家更好的理解jvm。

  

Java虚拟机组成详解的更多相关文章

  1. Elasticsearch Java 虚拟机配置详解

    Elasticsearch对Java虚拟机进行了预先的配置.通常情况下,因为这些配置的选择还是很谨慎的,所以你不需要太关心,并且你能立刻使用ElasticSearch. 但是,当你监视ElasticS ...

  2. Elasticsearch Java虚拟机配置详解(转)

    引言: 今天,事情终于发生了.Java6(Mustang),是2006年早些时候出来的,至今仍然应用在众多生产环境中,现在终于走到了尽头.已经没有什么理由阻止迁移到Java7(Dolphin)上了. ...

  3. JVM(二)Java虚拟机组成详解

    导读:详细而深入的总结,是对知识"豁然开朗"之后的"刻骨铭心",想忘记都难. Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我 ...

  4. Java虚拟机内存详解

    概述 Java虚拟机会自动管理内存,不容易出现内存泄漏和内存溢出问题.Java虚拟机会在执行过程中将管理的内存分为若干个不同的数据区域. 运行时数据区域 在jdk1.8之前的版本与1.8版本略有不同, ...

  5. JVM(Java虚拟机)详解(JDK7)

    1.Java内存区域 运行时数据区域: Java 虚拟机在执行Java程序时,定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁.另外一些则是与线程 ...

  6. Java虚拟机JVM详解

    一.JVM内存管理 1.1JVM运行时数据区 1.1.1程序计数器:记录当前线程正在执行的字节码指定的地址(行号) 为什么需要它:程序容易被打断 1.1.2虚拟机栈:存储当前线程运行方法时所需要的数据 ...

  7. JAVA对象头详解(含32位虚拟机与64位虚拟机)

    为什么要学习Java对象头 学习Java对象头主要是为了解synchronized底层原理,synchronized锁升级过程,Java并发编程等. JAVA对象头 由于Java面向对象的思想,在JV ...

  8. JAVA IO 类库详解

    JAVA IO类库详解 一.InputStream类 1.表示字节输入流的所有类的超类,是一个抽象类. 2.类的方法 方法 参数 功能详述 InputStream 构造方法 available 如果用 ...

  9. JAVA命令参数详解

    JAVA命令参数详解 JAVA命令详解 结构 说明 Java 和 OldJava JIT 选项 另请参阅 结构 java [ options ] class [ argument ... ] java ...

随机推荐

  1. Linux vim编辑器常用命令

    Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器 常用的vim命令如下图 补充: num+命令 对命令执行num次,如  5dd:剪切一行 * 5  即剪切5行,其它如此 /text   ...

  2. 出现 Request Entity Too Large问题的解决方法

    根据经验判断应该是上传文件大小被限制了,检查了应用配置是10M,把它设置成100M,重启服务也不能解决问题. 原来我们的tomcat是通过nginx发现服务代理的,问题就出现nginx服务器上,原来n ...

  3. java 多线程 day08 java5多线程新特性

    /** * Created by chengtao on 17/12/3. */public class Thread0801_java5_Atomaic { /* 三个包: http://tool. ...

  4. phpstudy2016 redis扩展 windows

    第一步,查看环境的信息. 第二步,根据线程是否安全.架构32位或64位下载redis扩展. http://pecl.php.net/package-stats.php 第三步,php_redis.dl ...

  5. mysql相关配置

    http://www.cnblogs.com/cnblogsfans/archive/2009/09/21/1570942.html http://www.jb51.net/article/31902 ...

  6. python全栈开发从入门到放弃之初识面向对象

    面向过程 VS 面向对象 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的复 ...

  7. crm 使用stark组件

    # Create your models here. from django.db import models class Department(models.Model): "" ...

  8. C# 使用windows服务发送邮件

    最近做了一个使用 C# 写了一个发送邮件的 windows 服务,在这里记录一下. 首先使用 Visual Studio 2015 创建一个 windows 服务项目. 然后在设计器上面右击添加安装程 ...

  9. 264. Ugly Number II(丑数 剑指offer 34)

    Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...

  10. XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem D. Great Again

    题目: Problem D. Great AgainInput file: standard inputOutput file: standard outputTime limit: 2 second ...