1 什么是JVM?

   JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范。比如 对Class文件类型,运行时数据,帧栈 ,指令集等的规范 ,Hotspot是使用JVM规范的商用产品,除此之外还有Oracle JRockit、IBM的J9也是JVM实现。

2 JVM和Java的关系

  Java语言本身与JVM没有太打的关系,Java语言的编译程序只需将由Java语言编写的.java文本,编译成在JVM上运行的.class文件的字节码。

  

3 JVM的内部体系结构:

  类装载器(ClassLoader)子系统,运行时数据区,和执行引擎。

  

  

3.1 类装载器(ClassLoader)子系统

3.2 运行时数据区

  3.2.1方法区域(Method Area)

  

  方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息/常量//静态信息/即时编译器编译后的代码等数据.虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来.

  对于习惯在HotSpot虚拟机上开发,部署程序的开发者来说,很多人都更愿意把方法区成为”永久代”(Permanent Generation),本质上两者并不相等,仅仅是因为HotSpot虚拟机的设计团队选择把GC分代收集扩展至方法区,或者说使用永久代来实现方法区而已,这样HotSpot的垃圾收集器可以像管理Java堆一样管理这部分内容,能够省去专门为方法区编写内存管理代码的工作.对于其他虚拟机(如BEA JRockit/ IBM J9)来说是不存在永久代的概念的.原则上,如何实现方法区属于虚拟机实现细节,不受虚拟机规范约束,但是使用永久代来实现方法区,现在看来并不是一个好主意,因为这样更容易遇到内存泄漏问题(永久代有-XX:MaxPermSize的上限,J9和JRockit只要没有触碰到进程可用内存的上限,例如:32位操作系统中的4GB,就不会出现问题),而且有极少的方法(例如String.intern())会因为这个原因导致不同虚拟机下有不同的表现.因此,对于HotSpot虚拟机,根据官方发布的路线图信息,现在也有放弃永久代并逐步采用Native Memory来实现方法区的规划了,在目前已经发布的JDK1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出.

  Java虚拟机规范对方法区的限制非常宽松,除了和Java堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集.相对而言,垃圾收集行为在这个区域是比较少出现的,但是并非数据进入了方法区就如同进入永久代的名字一样”永久”存在了.这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说,这个区域的回收”成绩”比较难以令人满意,尤其是对类型的卸载,条件相当苛刻,但是这部分区域的回收确实是存在必要的.在Sun公司的BUG列表里,曾出现过的若干个严重的BUG就是由于低版本的HotSpot虚拟机对此区域未完全回收而导致内存泄漏.

  根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常.

  1、类型信息

  类型的全限定名
  超类的全限定名
  直接超接口的全限定名
  类型标志(该类是类类型还是接口类型)
  类的访问描述符(public、private、default、abstract、final、static)
  2、类型的常量池

  存放该类型所用到的常量的有序集合,包括直接常量(如字符串、整数、浮点数的常量)和对其他类型、字段、方法的符号引用。常量池中每一个保存的常量都有一个索引,就像数组中的字段一样。因为常量池中保存中所有类型使用到的类型、字段、方法的字符引用,所以它也是动态连接的主要对象(在动态链接中起到核心作用)。

  3、字段信息(该类声明的所有字段)

  字段修饰符(public、protect、private、default)
  字段的类型
  字段名称
  4、方法信息

  方法信息中包含类的所有方法,每个方法包含以下信息:

  方法修饰符
  方法返回类型
  方法名
  方法参数个数、类型、顺序等
  方法字节码
  操作数栈和该方法在栈帧中的局部变量区大小
  异常表
  5、类变量(静态变量)

  指该类所有对象共享的变量,即使没有任何实例对象时,也可以访问的类变量。它们与类进行绑定。

  6、 指向类加载器的引用

  每一个被JVM加载的类型,都保存这个类加载器的引用,类加载器动态链接时会用到。

  7、指向Class实例的引用

  类加载的过程中,虚拟机会创建该类型的Class实例,方法区中必须保存对该对象的引用。通过Class.forName(String className)来查找获得该实例的引用,然后创建该类的对象。

  8、方法表

  为了提高访问效率,JVM可能会对每个装载的非抽象类,都创建一个数组,数组的每个元素是实例可能调用的方法的直接引用,包括父类中继承过来的方法。这个表在抽象类或者接口中是没有的,类似C++虚函数表vtbl。

  运行时常量池(Runtime Constant Pool)

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

Java虚拟机对Class文件每一部分(自然也包括常量池)的格式都有严格规定,每一个字节用于存储哪种数据都必须符合规范上的要求才会被虚拟机任何/装载和执行,但是对于运行时常量池,Java虚拟机规范没有做任何细节的要求,不用的提供上实现的虚拟机可以按照自己的需要来实现这个内存区域.不过,一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中.

运行时常量池相对于Class文件常量池的另外一个重要特征就是具备动态性,Java语言并不要求常量一定只有在编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法.其中intern()方法描述如下:

既然运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常.

  存储位置
  在JDK1.6及以前,运行时常量池是方法区的一部分。
  在JDK1.7及以后,运行时常量池在Java 堆(Heap)中。

运行时和class常量池一样,运行时常量池也是每个类都有一个

  3.2.2 堆(Heap)

  它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。

  3.2.3虚拟机栈

  线程中方法执行的模型,每个方法执行时,就在虚拟机栈中创建一个栈帧,每个方法从调用执行的过程,就对应着栈帧的虚拟机中从入栈到初战的过程,虚拟机由多个栈帧组成,一个线程会执行一个或多个方法,一个放过对应一个栈

      

5 执行引擎

认识 JVM的更多相关文章

  1. 46张PPT讲述JVM体系结构、GC算法和调优

    本PPT从JVM体系结构概述.GC算法.Hotspot内存管理.Hotspot垃圾回收器.调优和监控工具六大方面进行讲述.(内嵌iframe,建议使用电脑浏览) 好东西当然要分享,PPT已上传可供下载 ...

  2. java 利用ManagementFactory获取jvm,os的一些信息--转

    原文地址:http://blog.csdn.net/dream_broken/article/details/49759043 想了解下某个Java项目的运行时jvm的情况,可以使用一些监控工具,比如 ...

  3. Jvm 内存浅析 及 GC个人学习总结

    从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言.这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序.今天我们就来说说Java的一项基本但非常重要的技术内存管理 了解C ...

  4. JVM类加载

    JVM的类加载机制就是:JVM把描述类的class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型 ClassLoader JVM中的ClassLoade ...

  5. Java虚拟机 JVM

    finalize();(不建议使用,代价高,不确定性大) 如果你在一个类中覆写了finalize()方法, 那么你可以在第一次被GC的时候,挽救一个你想挽救的对象,让其不被回收,但只能挽救一次. GC ...

  6. 在 Linux 中安装 Oracle JDK 8 以及 JVM 的类加载机制

    参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...

  7. MapReduce剖析笔记之六:TaskTracker初始化任务并启动JVM过程

    在上面一节我们分析了JobTracker调用JobQueueTaskScheduler进行任务分配,JobQueueTaskScheduler又调用JobInProgress按照一定顺序查找任务的流程 ...

  8. java太low,又舍不得jvm平台的丰富资源?试试kotlin吧(一)

    尝试kotlin的起因 因为各种原因(版权,人员招聘),公司的技术体系从c#转到了java,我花了大概两周的时间来上手java,发现java的语法还是非常简单的,基本看着代码就知道什么意思.学习jav ...

  9. Jvm --- 常用工具

    jps:虚拟机进程状况工具 JVM Process Status Tool. 可以列出所有目前正在运行虚拟机的进程. jps -l 详细参数: -q 输出LVMID,省略主类名称 -m 输出虚拟机进程 ...

  10. JVM虚拟机结构

    JVM的主要结构如下图所示,图片引用自舒の随想日记. 方法区和堆由所有线程共享,其他区域都是线程私有的 程序计数器(Program Counter Register) 类似于PC寄存器,是一块较小的内 ...

随机推荐

  1. php目录函数操作,以及使用递归

    opendir 找到对应的目录 将目录中所有文件全部读入到内存(包含子文件夹下的所有文件) 将目录指针指向第一个文件 readdir 读取当前指针所指向的文件的文件名 2.将目录指针向下移动一位 ch ...

  2. 使用vue开发输入型组件更好的一种解决方式(子组件向父组件传值,基于2.2.0)

    (本人想封装一个带有input输入框的组件) 之前使用vue开发组件的时候,在遇到子组件向父组件传递值时我采用的方法是这样的: 比如子组件是一个输入框,父组件调用时需要获取到子组件输入的值,子组件通过 ...

  3. linux下yum安装python3

    linux下yum安装python3 linux下yum安装python3yum install python34 -ypython3 --version wget --no-check-certif ...

  4. docker安装各类软件

    安装Docker Docker 要求 CentOS 系统的内核版本高于 3.10 , uname -r 命令查看你当前的内核版本 1 安装一些必要的系统工具: sudo yum install -y ...

  5. 【NOIP2016提高A组模拟9.17】小a的强迫症

    题目 分析 题目要求第i种颜色的最后一个珠子要在第i+1种颜色的最后一个珠子之前, 那么我们从小到大枚举做到第i种,把第i种的最后一颗珠子取出,将剩下的\(num(i)-1\)个珠子插入已排好的前i- ...

  6. Electron开发使用Vue Devtools

    转自 [https://orchidflower.oschina.io/2017/03/29/Using-Vue-Devtools-in-Electron/] 2.2 安装步骤 首先在Chrome中安 ...

  7. 11.Linux date命令的用法

    date命令常的日常应用   修改时间 date -s “2008/05/23 19:20″ 打包文件 tar zcvf log-$(date +$F).gz /home/admin/logs 同步阿 ...

  8. selenium,控制滚动条

    今天写selenium用例的时候,遇见奇葩的问题,FF下是没有错误的,但是在chrome和ie下就会有问题,后来发现是 操作中点击一个按钮,在页面不可见,就会导致异常,解决方法如下: element ...

  9. ArrayList,Vector ,LinkedList的存储性能和特性

    ArrayList,Vector,LinkedList : 两者都采用数组元素方式存储数据,此数组元素数大于实际存储的数据(以便于增加和插入元素),允许直接按照序号索引元素,但是插入元素涉及数组元素移 ...

  10. 5.并发编程-synchronized 细节说明

    并发编程-synchronized 细节说明 1. synchronized-锁重入 & 异常释放锁 说明 * 关键字synchronized 拥有锁重入的功能,也就是在使用synchroni ...