JVM架构

java虚拟机简介

java虚拟机可能指如下三个不同的东西

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

每个java程序都运行在某个具体的java虚拟机实现实现的实例上。一个java虚拟机的实例负责运行一个java程序。当启动一个java程序的时候,一个虚拟机的实例也就诞生。当该程序退出时,这个虚拟机实例也实例也就随之消亡。

线程介绍

在java虚拟机内部有两种线程:

  • 守护线程 : 通常是由虚拟机自己使用,比如GC线程。但是,java程序也可以把它自己创建的任何线程标记为守护线程(public final void setDaemon(boolean on) )来设置,但必须在start()方法之前调用)。
  • 非守护线程 : main方法执行的线程,我们通常也称为用户线程上。

只要有任何的非守护线程在运行,java程序也会继续运行。当该程序中所有的非守护线程都终止时,虚拟机实例将自动退出(守护线程随JVM一同结束)。

** 守护线程中不适合进行IO、计算等操作,因为守护线程在所有的非守护线程退出后结束,这样并不能判断守护线程是否完成了相应的操作,如果非守护线程退出后,还有大量的数据没来得及读写,这将造成严重后果 ** 。

web服务器中的serlet,容量启动后初始化一个服务线程,即调度线程,负责处理http请求,然后每个请求过来调度线程池中取出一个工作者线程处理请求,从而实现并发控制的目的。

java虚拟机体系结构

jvm-architecture.png

每一个java虚拟机都有一个类装载器子系统,他根据给定的全限定名装载类型。同样每个java虚拟机都有一个执行引擎,它负责执行那些包含在被装载类的方法中的指令。 ** 当java虚拟机运行一个程序时,它需要内存来存储很多东西,例如:字节码,从已装载的class文件中得到的其它信息,程序创建的对象,传递给方法的参数,返回值,局部变量,以及运算的中间结果等,java虚拟机把这些东西都组织到几个"运行时数据区"中,以便管理。 **

** 每个java虚拟机实例都有一个方法区以及一个堆 ** ,他们是由 ** 该虚拟机实例中所有线程共享的 ** 。当虚拟机装载一个class文件时,它会从这个class文件包含的二进制数据中解析类型信息。** 然后把这些类型信息放到方法区中 **。当程序运行的时候,虚拟机会把所有该程序在运行时创建的对象都放到堆中。
** 每个新线程都会得到它自己的pc寄存器(程序计数器)以及一个java栈。 **

  • 如果线程正在执行的是一个java方法(非native方法)。那么pc寄存器的值将指向下一条将执行的指令,而它的java栈则总是存储该线程中java方法调用的转台 - 包括它的局部变量,被调用时传进来的参数,返回值以及运算的中间结果等等。
  • native方法调用的状态,则是以某种依赖于具体的方式存储在本地方法栈中,也可能是在寄存器或其它某些与特定实现相关的内存区中。

** java栈是由很多的栈帧(stack frame)或者说帧(frame)组成的,一个栈帧包含一个java方法调用状态 **。当现场调用一个java方法的时候,虚拟机压入一个新的栈帧到该线程的java栈中:当该方法返回时,这个栈帧被从java栈中弹出并抛弃。

java虚拟机没有指令寄存器,其指令使用java栈来存储中间数据。这样设计的原因是为了保持java虚拟机的指令集尽量紧凑,同时也便于java虚拟机在那些只有很少通用寄存器的平台上实现。另外,java虚拟机这种基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。

jvm-thread-data-area.png

1.这些内存区域是私有的,任何线程都不能访问另外一个线程的pc寄存器或java栈。
2.图中是一个虚拟机实例的快照,它有三个线程正在执行,线程1和线程2都正在执行java方法,而线程3在执行native方法。

数据类型

数据类型分为两种:

  • 基本类型:基本类型的变量持有原始值。
  • 引用类型:引用类型的变量持有引用值。引用值是指对某个对象的引用,而不是该对象本身。
jvm-data-type.png

基本类型

** java语言中的所有基本类型都是java虚拟机中的基本类型。但boolean有点特别,虽然java虚拟机也把boolean看作基本类型,但指令集对boolean只有很有限的支持。 ** 当编译器把java源码编译成字节码时,它会用int或byte来表示boolean。在java虚拟机中false是由整数 '0' 表示,所有的非零整数都表示true。 ** 涉及boolean值的操作则会用int,另外boolean数组是当做byte数组来访问的 ** ,但是在"堆"区,它也可以被表示为位域。

** java虚拟机的基本数据类型的值域在任何地方都是一致的 ** ,比如 : 不管底层主机平台是什么,一个'long'在任何虚拟机中总是一个64位二进制补码表示的。

java虚拟机中有一个值在内部使用的基本类型 ‘returnAddress’,java程序员不能使用这个类型。 ** 这个基本类型是用来实现java程序中的finally子句的 ** 。

引用类型

java虚拟机中有三种引用类型,它们的值都是对动态创建对象的引用:

  • 类类型 : 类实例(对象)的引用。
  • 接口类型 : 是对实现了该接口的某个类实例的引用。
  • 数组类型 : 数组对象的引用,在java虚拟中数组是个真正的对象。

还有一个特殊的引用值 -- null,它表示引用变量没有引用任何对象。

java虚拟机规范定义了每一种数据类型的取值范围,但没有定义它们的位宽。存储这些类型的值所需的点位宽度,是由具体的虚拟机实现的设计者决定的。

jvm-data-arrange.png

类装载器

java类加载器是java运行环境(java runtime environment)的一部分,负责动态加载java类到java虚拟机的内存空间中。 ** 类通常是按需加载,即第一次使用该类时才加载 ** 。由于有了类加载器, java运行时系统不需要知道文件与文件系统。每个java类型必须由某个类加载器装入到内存。

类装载器子系统涉及java虚拟机的其他几个组成部分,以及几个来自java.lang库的类。比如,用户自定义的类装载器只是普通的java对象,它的类必须派生自java.lang.ClassLoaderClassLoader中定义的方法为程序提供了访问类装载器机制的接口。此外,对于每个被装载的类型,java虚拟机都会为他创建一个java.lang.Class类的实例代表该类型。和所有其他的对象一样,用户自定义的类装载器以及Class类的实例都放在内存中的堆区,而装载的类型信息都位于方法区。

类装载器子系统除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为变量分配初始化内存,以及帮助解析符号引用。这些动作必须严格按一下顺序完成:

  1. 装载 -- 查找并装载类型的二进制数据。
  2. 链接 -- 执行验证,准备以及解析(可选)
    • 验证 确保被导入类型的正确性
    • 准备 为类变量分配内存,并将其初始化为默认值。
    • 解析 把类型中符号引用转换为直接引用。
  3. 初始化 -- 把类变量初始化为正确的初始值。

方法区

jvm-method-const-area.png

** 在java虚拟机中,关于被装载类型的信息存储在逻辑上一个被称为方法区的内存中 ** 。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件 -- 一个线性二进制数据流,然后 把它传输到虚拟中。紧接着虚拟机提取其中的类型信息,并将这些信息存储方法区。该类型的类(静态)变量同样也是存储在方法区内的。

当虚拟机运行java程序时,它会查找使用存储在方法区中类型信息。

** 由于所有线程都共享方法区,因此他们对方法区的访问必须设计为线程安全的 ** 。方法区的大小不必是固定的,虚拟机可以根据应用需要动态调整。同样,方法区也不必是连续的,方法区可以在一个堆中自由分配。方法区也可以被垃圾收集 -- 这时涉及到类的卸载。

方法区中包含的信息:

  1. 类型信息 : 对每个装载的类型,虚拟机都会在方法区存储一下信息
  • 这个类型的全限定名
  • 这个类型的直接父类的全限定名
  • 这个类型是类类型还是接口类型
  • 这个类型的访问修饰符
  • 任何直接父接口的全限定名的有序列表
  1. 常量池 : 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用常量的一个有序集合,包含直接发常量(String,Integer ...)和对其它类型、字段和方法的符号引用。池中的数据项通过索引访问。

  2. 字段信息

  3. 方法信息

  4. 类变量

  5. 编译时常量
    7.指向ClassLoader类的引用
    8.指向Class类的引用

  6. 方法表为了提高访问效率,虚拟机对每个装载的非抽象类都生成一个方法表,把它作为类信息的一部分,它主要存储了所有它的实例可能被调用的实例方法的直接引用,包括从父类继承的 实例方法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容

  • JVM内存模型Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: ...
    光剑书架上的书阅读 2,504评论 2 26
  • JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序...
    Solang阅读 1,174评论 0 19
  • 盛会空前京都开, 贤杰共商国是来。 中华圆梦强内力, 丝绸铺路筑高台。 ...
    竹影_张育清阅读 375评论 2 3
  • 下雨了, 丝丝的凉意, 慢慢地知道, 谁都给不了我想要的生活, 想要的生活都要靠自己去争取, 生活不会因为你多看了...
    折腾的那年2019阅读 150评论 0 0
  • 最近特别想干件事情,总觉得再不疯狂就要年老色衰,若干年以后要后悔。但是,经历过一段抓耳挠腮之后,还是不知道自己可以...
    莉丝lxb阅读 141评论 0 0