前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java程序运行原理分析

Java程序运行原理分析

作者头像
CodingDiray
发布2019-09-25 16:13:10
9890
发布2019-09-25 16:13:10
举报
文章被收录于专栏:Coding DiaryCoding Diary

class文件内容

  • class文件包含Java程序执行的字节码
  • 数据严格按照格式紧凑排列在class文件的二进制流,中间无分割符
  • 文件开头有一个0xcafebabe(16进制)特殊的标志

JVM运行时数据区

线程独占: 每个线程都会有它独立的空间,随线程的生命周期而创建和销毁 线程共享: 所有线程都能访问这块内存数据,随虚拟机或GC而创建和销毁 方法区

  • 方法区是各个线程共享的内存区域
  • 用于存储已被虚拟机加载的类信息, 常量,静态变量, 即时编译后的代码等数据
  • 虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分, 但它却有一个别名叫Non-Heap, 目的应该是与Java堆区分开来
  • Oracle的Hotspot虚拟机在Java7中方法区放在’永久代’(Permanent Generation), Java8放在元数据空间, 并且通过GC机制对这个区域进行管理
  • 运行时常量池是方法区的一部分 Java堆
  • Java堆是被所有共享的一块内存区域, 在虚拟机启动时创建
  • 存放对象的实例
  • 垃圾收集器的主要管理区域
  • Java堆还可以细分为: 新生代和老年代, 新生代又可以细分为Eden 空间, From Survivor空间 和To Survivor空间
  • 空间满了会抛OutOfMemoryError
Java虚拟机栈
  • Java虚拟机栈是线程私有的, 它的生命周期与线程相同
  • Java虚拟机栈描述的是Java方法执行的内存模型: 每个方法被执行的的时候都会同时创建一个栈帧(栈帧是方法运行时的基础数据结构)用于存储局部变量表, 操作栈, 动态链接, 方法出口等信息.
  • 栈内存默认最大是1M, 超出则抛出StackOverFlowError
本地方法栈
  • 本地方法栈与虚拟机栈的功能类似, 虚拟机栈是为虚拟机执行Java方法而准备的, 本地方法栈是为虚拟机使用Native本地方法而准备的
  • Hotspot虚拟机中虚拟机栈与本地方法栈的实现方式一样, 超出大小后也会抛StackOverFlowError
程序计数器
  • 程序计数器是线程私有的一块较小的内存空间
  • 记录当前线程执行的字节码位置, 存储的是字节码指令地址, 如果执行Native方法, 则计数器为空
  • CPU同一时间, 只会执行一条线程的指令. JVM多线程会轮流切换并分配CPU的执行时间的方式. 为了线程切换后, 需要通过程序计数器来恢复正确的执行位置 查看class文件内容 使用Demo.Java进行测试, 运行javac Demo.java编译成class文件, 然后运行javap -v Demo.class > Demo.txt查看class文件内容 Demo.Java public class Demo{ public static void main(String[] args){ int x = 500; int y = 100; int a = x / y; int b = 50; System.out.println(a + b); } } Demo.txt Classfile /E:/*/Demo.class Last modified 2019-6-30; size 412 bytes MD5 checksum efd785af33e58aa9fc9834110b74b87b Compiled from "Demo.java" public class Demo minor version: 0 //次版本号 major version: 52 //主版本号 版本号规则: JDK5,6,7,8分别对应49,50,51,52 flags: ACC_PUBLIC, ACC_SUPER //访问标志Constant pool: // 常量池 类信息包含的静态常量, 编译之后就能确认 #1 = Methodref #5.#14 // java/lang/Object."<init>":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = Methodref #17.#18 // java/io/PrintStream.println:(I)V #4 = Class #19 // Demo #5 = Class #20 // java/lang/Object #6 = Utf8 <init> #7 = Utf8 ()V #8 = Utf8 Code #9 = Utf8 LineNumberTable #10 = Utf8 main #11 = Utf8 ([Ljava/lang/String;)V #12 = Utf8 SourceFile #13 = Utf8 Demo.java #14 = NameAndType #6:#7 // "<init>":()V #15 = Class #21 // java/lang/System #16 = NameAndType #22:#23 // out:Ljava/io/PrintStream; #17 = Class #24 // java/io/PrintStream #18 = NameAndType #25:#26 // println:(I)V #19 = Utf8 Demo #20 = Utf8 java/lang/Object #21 = Utf8 java/lang/System #22 = Utf8 out #23 = Utf8 Ljava/io/PrintStream; #24 = Utf8 java/io/PrintStream #25 = Utf8 println #26 = Utf8 (I)V { public Demo(); // 默认隐式无参的构造函数 descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 public static void main(java.lang.String[]); //程序的入口main方法 descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC //访问控制 Code: stack=3, locals=5, args_size=1 //方法栈栈帧中操作数栈的深度,本地变量数量,参数数量 0: sipush 500 //Jvm执行引擎执行这些源码编译过后的指令码, javap翻译出来的 3: istore_1 //是操作符, class 文件内存储的是指令码, 前面的数据是偏移量, 4: bipush 100 //Jvm根据这个去区分不同的指令. 详情参照'JVM指令码表' 6: istore_2 7: iload_1 8: iload_2 9: idiv 10: istore_3 11: bipush 50 13: istore 4 15: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 18: iload_3 19: iload 4 21: iadd 22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 25: return LineNumberTable: line 3: 0 line 4: 4 line 5: 7 line 6: 11 line 7: 15 line 8: 25 } SourceFile: "Demo.java" 程序完整运行分析
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Coding Diary 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • class文件内容
    • Java虚拟机栈
      • 本地方法栈
        • 程序计数器
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档