JVM划分和执行流程

JVM

JVM是Java Virtual Machine (Java虚拟机)的缩写,是一种用于计算设备的规范

跨平台

编写Java代码后,编译后会生成.class文件,俗称字节码,而JVM虚拟机就是负责将这些字节码文件翻译成特定平台的机器码后运行,也是说在不同的平台(wind、mac、Linux...)安装不同的JVM虚拟机,那么就可以运行.class,而目前能编译成.class语言也有很多种,如下:

JVM跨平台

优点

  • 一套指定,多端运行
  • 使用者多,框架多
  • 成熟的GC回收机制
  • 可移植性

缺点

  • JVM启动太重
  • 性能会有局面性

运行时流程图

  • 一套字节码指令集class文件
  • 类加载器
  • 方法区
  • Java栈
  • 本地方法栈
  • 程序计数器
  • 执行引擎
  • 本地方法接口
  • 本地库
JVM运行时流程图
  • 绿色【方法区、堆】:运行时数区所在的线程共享
  • 黄色【Java栈、本地方法栈、程序计数器】:运行时数区线程私有

类加载器:在以前文章 插件化开发 -- 类加载 有介绍过

运行时数区也是本文的重点

运行时数据区域(重点)

JVM运行时数据区域

定义

当程序Run跑起来,必然会有一个线程(多数为主线程Main-Thread),Java虚拟机会把它所管理的 内存 划分成若干个不同的数据区域

类型

  • 线程共享区
  • 线程私有区

Java方法运行内存区域

有俩大点分别为:程序计数器虚拟机栈

程序计数器

指向当前线程正在执行的字节码指定的地址,一般是对应当前操作数栈的顶端栈帧的位置,防止线程阻塞后被唤醒不知道之前执行的位置点。

虚拟机栈

Java虚拟机栈,除了Native方法需要在本地方法栈计算,Java的一般方法函数计算都是在虚拟机栈完成,具有重要性,具有存储当前线程运行方法,一个方法函数,理解为一个(main-栈帧),栈帧存储了方法局部变量表、操作数栈、动态连接和返回地址等信息。

每一个方法调用至执行完成的过程,都对应着一个栈帧在虚拟机里从入栈到出栈的过程

虚拟机栈(Stack)
方法栈帧
  • 局部变量表

    方法内部的一些变量,参数值,以及一行代码“=”左边的结果集

  • 操作数栈

    常称为操作栈,数据结构是栈(Stack),具有先进后出(FILO)、后进先出(LIFO)特性,当一个方法刚刚执行,其操作数栈是空的,随着方法执行和字节指定,会从局部变量表或对象实例的字段中复制常量、变量写入到操作数栈,随着计算的进行将栈中元素出栈到局部变量或者是返回出口给调用者,会频繁的进/出栈操作。

  • 动态连接

    Class中一个方法需要调用其他方法,需要将这些方法的符号引用转化为其他内存地址的直接引用,而符号引用就存在方法区的运行时常量池,每个栈帧都有一个指向了运行时常量池中该栈所属的符号引用,这个引用的目的就是为了支持调用过程中的动态连接。

  • 方法返回出口

    • 正常完成出口
    • 异常完成出口

分析操作数栈

一段代码:

    public int add(int a, int b) {
        int c = 0;
        c = a + b;
        return c;
    }

    public static void main(String[] args) {
        Presenter presenter = new Presenter();
        int outcome = presenter.add(10, 20);
    }

通过 javac Presenter.java 编译成class文件,JVM可以编译的文件,

在通过 javap -c Presenter.class JVM将class字节码进行反编译生成汇编代码

  public int add(int, int);
    Code:
       0: iconst_0      //将int类型常量0压入栈, 计数器标记0位置
       1: istore_3      //将int类型值存入局部变量3, 计数器标记1位置
       2: iload_1       //从局部变量1中装载int类型值, 计数器标记2位置
       3: iload_2       //从局部变量2中装载int类型值, 计数器标记3位置
       4: iadd          //执行int类型的加法, 计数器标记4位置
       5: istore_3      //将int类型值存入局部变量3, 计数器标记5位置
       6: iload_3       //从局部变量3中装载int类型值, 计数器标记6位置
       7: ireturn       //从方法中返回int类型的数据, 计数器标记7位置

  public static void main(java.lang.String[]);
    Code:
       0: new           #2  //创建一个新对象   #2动态连   // class com/neng/jvm/Presenter
       3: dup               //复制栈顶数值并将复制值压入栈顶
       4: invokespecial #3  //调用需要特殊处理的实例方法 #3动态连 // Method "<init>":()V
       7: astore_1          //将引用类型或returnAddress类型值存入局部变量1
       8: aload_1           //从局部变量1中装载引用类型值
       9: bipush        10  //将一个10位带符号整数压入栈,   计数器会占用多个9的位置
      11: bipush        20  //将一个20位带符号整数压入栈
      13: invokevirtual #4                  // Method add:(II)I
      16: istore_2          //将int类型值存入局部变量2, 计数器标记为16
      17: return            //从方法中返回,返回值为void

通过指令表操作流程:

局部变量表,类似于数据表,自带物理位置,存储当前(函数)栈帧this常量、计算结果,代码左边

操作数据栈,计算逻辑结果,即使一个常量变量也要先进入栈,再弹栈进入局部表,代码右边

计数器对操作数据栈的位置记录

《JVM 字节码指令集》 帮助查询:

变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_
 
操作数栈到变量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstor_,astore,astore_
 
常数到操作数栈:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,iconst_,lconst_,fconst_,dconst_
 
加:iadd,ladd,fadd,dadd
 
减:isub,lsub,fsub,dsub
 
乘:imul,lmul,fmul,dmul
 
除:idiv,ldiv,fdiv,ddiv
 
余数:irem,lrem,frem,drem
 
取负:ineg,lneg,fneg,dneg
 
移位:ishl,lshr,iushr,lshl,lshr,lushr
 
按位或:ior,lor
 
按位与:iand,land
 
按位异或:ixor,lxor
 
类型转换:i2l,i2f,i2d,l2f,l2d,f2d(放宽数值转换)
i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f(缩窄数值转换)
 
创建类实例:new
 
创建新数组:newarray,anewarray,multianwarray
 
访问类的域和类实例域:getfield,putfield,getstatic,putstatic
 
把数据装载到操作数栈:baload,caload,saload,iaload,laload,faload,daload,aaload
 
从操作数栈存存储到数组:bastore,castore,sastore,iastore,lastore,fastore,dastore,aastore
 
获取数组长度:arraylength
 
检相类实例或数组属性:instanceof,checkcast
 
操作数栈管理:pop,pop2,dup,dup2,dup_xl,dup2_xl,dup_x2,dup2_x2,swap
 
有条件转移:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonnull,if_icmpeq,if_icmpene,
if_icmplt,if_icmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne,lcmp,fcmpl
fcmpg,dcmpl,dcmpg
 
复合条件转移:tableswitch,lookupswitch
 
无条件转移:goto,goto_w,jsr,jsr_w,ret
 
调度对象的实例方法:invokevirtual
 
调用由接口实现的方法:invokeinterface
 
调用需要特殊处理的实例方法:invokespecial
 
调用命名类中的静态方法:invokestatic
 
方法返回:ireturn,lreturn,freturn,dreturn,areturn,return
 
异常:athrow
finally关键字的实现使用:jsr,jsr_w,ret

内存区域以及如何分配

JVM在内存处理的流程步骤:

  1. JVM申请内存
  2. 初始化运行时数据区
  3. 类加载
  4. 执行方法栈
  5. 创建对象

其中代码运行Run,不停的对4,5轮询的操作,进栈出栈,进局部变量表

代码对象如何在JVM分配呢?

本地方法栈:

  • 存放各种Native方法的局部变量表之类的信息
  • 和虚拟机栈类似,内部结构也是栈帧,每个Native方法执行创建一个栈帧
  • 没有明确的规定内存大小

虚拟机栈

  • 线程执行方法的时候内部存储的局部变量会从堆中对象的地址
  • 线程是私有的,与线程同一时候创建,内部有局部变量表存储
  • 栈大小如果是固定,压栈大于最大值,就抛出 StackOverflowError
  • 栈大小如果是动态扩展,当超过内存空间支持,则抛出 OoutofMemoryError

程序计数器

  • 记录当前执行线程执行到哪一条字节码指定(位置标记)

方法区

  • 类型信息,类加载信息,被虚拟机加载的类元数据信息

  • 常量、静态变量、以及编译器编译后的代码(运行常量池,例如【String】 “Hello Word” )

  • 对象/数组地址指向堆

堆区

  • 存放Java对象和数组,(字符串常量池-jdk8)

  • 虚拟机中内存存储空间比较大的区域

  • 可能出现OOM异常区域

  • 该区域是GC的主要区域,堆区是有 年轻代 和 老年代 组成,频繁被GC回收,常量对象未被回收,就会由新转换老

    JVM堆区的参数设置
    # 设置堆区的初始大小
    -Xms1024m
    # 设置堆区的存储空间最大值,一般与堆区的初始大小相等
    -Xmx1024m
    # 设置年轻代堆的大小
    -Xmn512m
    # 设置如下参数,在出现OOM时进行堆转储
    -XX:+HeapDumpOnOutOfMemoryError
    # 设置以上设置时,需配置以下参数,堆转储文件输出的位置
    -XX:HeapDumpPath=/usr/log/java_dump.hprof
    
参考:

《JVM 字节码指令集》

ava虚拟机—栈帧、操作数栈和局部变量表

从 Java 代码如何运行聊到 JVM 和对象的创建-分配-定位-布局-垃圾回收

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