zoukankan      html  css  js  c++  java
  • Java程序运行原理分析

    class文件内容

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

    img

    JVM运行时数据区

    img

    线程独占: 每个线程都会有它独立的空间,随线程的生命周而创建和销毁

    线程共享: 所有线程都能访问这块内存数据,随虚拟机或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"
    

    程序完整运行分析

    img
    img

  • 相关阅读:
    PHP中读写文件
    Java和PHP在Web开发方面的比较
    CentOS yum安装 Apache + PHP + MySQL
    PHP 时间参数大全
    数据库结果太大,PHP超出内存限制
    PHP扩展配置?
    php 实现KMP算法
    OS + Linux Shell bash / sh / ksh / csh / tcsh / adb shell
    my soft / text tools / EmEditor / Notepad++ / UltraEdit / EditPlus / Sublime Text
    JAVA EE Projects_sourceforge
  • 原文地址:https://www.cnblogs.com/coding-diary/p/11153765.html
Copyright © 2011-2022 走看看