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方法则为空。线程隔离。 多线程中记录某一个线程的执行进度。方便在线程切换后恢复执行位置。
程序运行分析: