JVM系列(一):JVM内存模型

一、JVM介绍

JVM(Java virtual machine)是一种虚拟机,本身用C语言编写,用来屏蔽不同操作系统的细节,使得Java代码经过一次编译即可在不同的系统上运行。如图所示:
我们用javac命令,就是将Java源文件(.java)编译成Java字节码文件(.class)文件,而jvm会把.class文件翻译成机器码以实现Java的跨平台性。
这里跟C和C++做个比较:

  • C和C++语言也是跨平台的,不过他们的跨平台是在编译器级别的,不同平台要用不同编译器来编译代码,并且在源码级别要对不同平台做相应处理,所以C和C++有“一次编写,到处编译”的说法。
  • Java的跨平台是通过JVM实现的,JVM帮开发者屏蔽了不同平台的细节,同样的源码只经过一次编译就可以在不同的平台上运行,这也就是Java的“一次编写,到处运行”。同时这也是Java速度比C、C++慢的原因,因为Java代码要经过JVM的翻译才可以跟操作系统交互,并且Java的垃圾回收机制也会消耗大量时间。


二、JVM的内存模型

JVM的内存模型即Java的运行时数据区,也就是Java程序在运行时,各种数据存放的地方,基本结构如图:




图一是JVM内存基本结构,分为线程共享区和非线程共享区,图二是比较详细的版本,其中堆又分为新生代和老年代,新生代又分为Eden区和两个Survivor区,下面针对图一来详细说明JVM内存结构。

  1. 非线程共享区
  • 程序计数器: 程序计数器是用于标识当前线程执行的字节码文件的行号指示器。多线程情况下,每个线程都具有各自独立的程序计数器,所以该区域是非线程共享的内存区域。
    通俗点说,程序计数器用来记录当前线程的代码执行到哪里了,那么为啥要记录呢?我一行一行执行不就行了吗?其实在多线程环境中,如果当前线程被挂起了,那恢复的时候怎么知道上次执行到哪里了?这时候程序计数器的作用就来了。
    比如说有个Hello.java:
public class Hello {

    int add() {
        int a = 1;
        int b = 2;
        int c = a + b;
        return c;
    }

    public static void main(String[] args) {
        Hello h = new Hello();
        int result = h.add();
        System.out.println(result);
    }
}

我们用javap -c命令来对class文件进行反汇编:

Compiled from "Hello.java"
public class file.Hello {
  public file.Hello();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  int add();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: istore_3
       8: iload_3
       9: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class file/Hello
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method add:()I
      12: istore_2
      13: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      16: iload_2
      17: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V
      20: return
}

代码中Code下的行号,就是程序计数器了。

  • 虚拟机栈
    虚拟机栈描述的是Java方法执行时的内存,每个方法在执行时都会创建一个栈帧(stack frame),每个方法从开始到结束都对应着一个栈帧从入栈到出栈的过程。栈帧又包含了局部变量表、操作数栈、动态链接和方法出口4个部分。

    • 局部变量表:存放方法参数和局部变量
    • 操作数栈: 操作数栈可理解为java虚拟机栈中的一个用于计算的临时数据存储区。以上面Hello类为例,
      iconst_1的作用就是定义第一个int常量,istore_1则将该值压入操作数栈,等运算的时候再进行弹栈(iload_1)。
    • 动态链接: 在运行时常量池中存有大量的符号引用,当栈帧A想调用栈帧B的方法时,就需要以B方法的符号引用作为参数,将符号引用转为直接引用来进行调用,这些符号引用一部分在类的加载阶段(解析)或第一次使用的时候就转化为了直接引用(指向数据所存地址的指针或句柄等),这种转化称为静态链接。而相反的,另一部分在运行期间转化为直接引用,就称为动态链接。
    • 方法出口:分为正常完成出口和异常完成出口
      正常完成出口:执行任意一个方法返回(如:return)的字节码指令,如有返回值则返回给调用者。
      异常完成出口:在方法执行过程中发生异常,且没有在方法体中进行处理。异常完成出口退出时,不会给上层调用者任何返回值。
  • 本地方法栈
    和虚拟机栈类似,只不过本地方法栈是为native方法服务的。

  1. 线程共享区
  • 方法区
    存放类信息,如类的字段、方法、常量等信息,在jdk1.8之前,方法区是位于永久代的,在jdk1.8之后,永久代已经被移除,方法区放在了元数据空间里。
    元数据空间(meta area)和之前的永久代类似,存放了类的一些基本数据和常量池,但元空间不是在JVM里的,而是使用的本地内存。


  • 存放Java对象和数组对象的地方,jvm内存结构中,堆占的空间是最多的,也是Java垃圾收集器工作的地方。
    堆分为新生代和老年代,新生代又分为Eden区和两个Survivor区,关于堆和垃圾收集器的内容,放在后面的文章讲解。

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