01 :Java程序运行原理

Class 文件内容?
        Class文件包含Java执行的字节码,数据是严格按照“Jvm规定的格式”排列的二进制流。
        文件头是:ca fe ba be(16进制咖啡宝贝)
        通过java -p  class可以看到:
           主/次版本号: version52:  // 版本号规则:JDK5,6,7,8 分别对应 49,50,51,52
           访问标识:  flags:ACC_PUBLIC,ACC_SUPER    // 对应一些访问的权限。
           常量池:Constant pool : 类信息包含的静态常量(类名称引用、方法名称引用、类本身用到的常量、自己创建的),编译后就可以确定。
           构造方法,main方法:可以看到方法被编译成了一条条的jvm执行指令。
Class加载后jvm运行时数据区?
        1:线程共享部分:
                A、方法区 
                        I、虚拟机规范中,方法区是一个逻辑区域,具体实现因虚拟机而异。
                        II、存放类信息、常量、编译后的代码、【静态变量(1.7移到了堆)】 。
                        III、版本1.7时方法区在永久代中。版本1.8方法区在元数据空间中,并通过GC管理。
                        IIII、方法区中有个区域叫做:“运行时常量池”。作用是将代码中的常量单独存放。
                B、堆内存
                        I、JVM启动时创建,存放对象实例。GC主要管理区域(垃圾堆)。会抛出:OutOfMemroyError。
                        II、老年代(Old)。
                        III、新生代  (Eden、So、S1三部分)。
        2:线程独占部分:
                A、虚拟机栈
                        I、线程独占(每个线程都从虚拟机栈空间中划分出一部分独立空间单独运行),每个线程有多个栈帧,每个栈帧相当于线程中执行的一个方法。
                        II、栈帧中包含:局部变量表、操作数栈、动态链接、方法返回地址、等。
                        III、默认大小是 1M ,超出后抛出StackOverflowError。
                        IIII、方法依次调用的过程中,栈帧会不断压栈弹栈。
                B、本地方法栈
                        I、本地方法栈是为了执行Native本地方法而准备的。
                        II、没有规范实现方式、不同的虚拟机厂商有不同的实现,HotSpot虚拟机实现方法和虚拟机栈实现类似。
                C、程序计数器
                        I、记录字节码执行的位置,存储的是字节码中指令的地址,如果是执行Native方法则为null
                        II、多线程切换时方便恢复正确的线程执行位置。
程序运行流程?
            1 编译: 源代码编译成字节码文件。
             2 加载: 所有相关的Class都被加载到方法区,Class中的常量加载到 “运行时常量池”
             3 运行:JVM会创建线程并为线程分配:虚拟机栈、本地方法栈、程序计数器
                            接下来:虚拟机栈、本地方法栈中:栈帧不断的压栈弹栈(对印着方法的调用)。
                                            程序计数器记录“字节码命令”执行的地址。
                                            其中每个栈帧中包含(方法内部命令执行时用。用于:加载值保存值运算值):
                                                    I、本地变量表
                                                    II、操作数栈
Jvm运行时数据区详细?
        “Java源代码”编译生成“.class字节码”
        class加载到JVM中,JVM给class分配不同数据区用于存储不同的数据。
        数据区是逻辑分区,不同的虚拟机有不同的实现。
                方法区:
                        存放类型信息:1、类信息:类的名称、修饰符、超类、接口等、常量、【静态变量(1.7移到了堆)】。
                                                  2、已加载类信息:字段信息、方法信息、该类的装载器引用、clas实例的引用等。
                        Oracle 的HotSpot虚拟机:
                1、 java1.7之前,方法区位于永久代(PermGen),永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值,不可变。
                2、 java1.7中,static变量从永久代移到堆中。
                3、 java1.8中,取消永久代,方法存放于元数据空间(Metaspace),并通过GC管理,元数据空间仍然与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中。
                堆内存:
                          存放对象,Jvm启动时创建,GC管理的主要区域,如果满了就会OutOfMemroyError,Java堆中还可以细分为:“新生代”和“老年代”;
       Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为”GC堆”(Garbage Collected Heap,幸好国内没有翻译成”垃圾堆”).
从内存回收的角度来看,由于现在收集器基本都采用分代收集算法,所以Java堆中还可以细分为:“新生代”和“老年代”;
       根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样.在实现时,既可以实现固定大小的,
    也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过
-Xmx和-Xms控制).如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,就会抛出OutOfMemoryError异常。 虚拟机栈: java方法执行的内存模型,线程隔离的(线程之间相互隔离)    方法调用时,创建栈帧,并压入虚拟机栈;方法执行完毕,栈帧出栈并被销毁    每个java方法在执行时,会创建一个“栈帧(stack frame)” 栈帧的结构分为“局部变量表、操作数栈、动态链接、方法出口”几个部分(这里只需要了解栈帧是一个方法执行时所需要数据的结构)。 我们常说的“堆内存、栈内存”中的“栈内存”指的便是虚拟机栈,确切地说,指的是虚拟机栈的栈帧中的局部变量表,因为这里存放了一个方法的所有局部变量。 虚拟机栈最大默认内存时1M,超出会报StackOverflowError。 本地方法栈: Native方法执行的内存模型,线程隔离的。 虚拟机规范没有具体的实现,由不同的厂商实现,Oracle 的HotSpot中本次方法栈和虚拟机栈的实现时类似的实现。 程序计数器: 记录当前执行的字节码的位置。存储的是字节码指令地址,如果是Native方法则为空。线程隔离。 多线程中记录某一个线程的执行进度。方便在线程切换后恢复执行位置。

 

    程序运行分析:

 

 

 

 

 
 
 
 

posted on 2020-03-30 20:36  笑明子  阅读(179)  评论(0编辑  收藏  举报

导航