您的位置:首页 > 其它

JVM Memory Model and Visibility(JVM内存模型与可见性)

2020-02-01 08:13 253 查看

1 Java Run Theory Analysis(Java运行原理分析)

1.1 Class文件结构

学过Java的都知道,Java文件先经过编译器编译成.class文件,那么.class文件是怎么样的结构呢?

public class Helloworld {

public static void main(String args[]){
System.out.println("hello world!!!");
}

}

这个Helloworld程序编译成.class文件之后,使用EditPlus以16进制打开,能看到文件的开头是以“CA FE BA BE”开头的。这里面还包括了版本、访问标志(public/private等)、常量池、当前类、父类、接口、字段、方法、属性。

1.2JVM运行时数据区简介


从这个图可以看出编译成.class文件之后,由JVM来加载class文件,并将class文件的内容在JVM数据区中进行处理。
线程独占:每个线程都会有它的独立地空间,随线程生命周期而创建和销毁
线程共享:所有线程能访问这块内存数据,随虚拟机或GC(垃圾回收)而创建和销毁
下面对JVM运行时数据区进行解释:
1、方法区:JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据,虚拟机规范中这是一个逻辑区域,不同的虚拟机其实现也是不同的,并且它是各个线程共享的内存区域。
如:oracle的HotSpot在JDK7中方法区放在永久代,JDK8则放在元数据空间,并且通过GC机制对这个区域进行管理。
2、堆内存:由老年代、新生代(细致点可分为Eden、From Survivor、To Survivor),JVM启动时创建,存放对象的实例。垃圾回收器主要就是管理堆内存。如果满了,就会出现OutOfMemoryError。
3、虚拟机栈:每个线程都在这个空间有自己的私人空间,线程栈由多个栈帧(Stack Frame)组成。一个线程会执行一个或多个方法,一个方法对应一个栈帧。
栈帧的内容包括:局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大是1M,超出则抛出StackOverflowError。
4、本地方法栈:与虚拟机栈类似,虚拟机栈是为虚拟机执行Java方法而准备的,本地方法栈是为虚拟机使用Native本地方法而准备的。虚拟机规范没有规定具体的实现,由不同的虚拟机厂商去实现。HotSpot虚拟机中虚拟机栈和本地方法栈的实现是一样的,超出大小之后会抛出StackOverflowError。
5、程序计数器:记录当前线程执行字节码的位置,存储是字节码指令地址,如果执行Native方法,则计数器值为空。每个线程都会在这个空间占据一定的私人空间,占用内存空间很小。CPU同一时间,只会执行一条线程中的指令,JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器,来恢复正确的执行位置(说白了程序计数器就是记录线程的执行位置的)。

1.3 Class文件内容解析,并JVM运行解析class文件过程

从一个最简单的代码开始:

public class Demo {
public static void main(String args[]){
int x = 100;
int y = 200;
int z = 200/100;
System.out.println(x + y);
}
}

使用javap –v Demo.class > Demo.txt就能够将解析出来的内容重定向到Demo.txt中。
部分内容如下:

minor version:0 —次版本号
major version:49 —主版本号(49-JDK5->52-JDK8)

Constant pool:常量池

Demo的源码中没有定义构造函数,但是编译完之后会有默认的无参构造函数。

具体指令,可以查指令码表:


接下来,分析一下通过查指令表的指令,来分析以上执行过程

首先,本地变量表中第0个参数是main方法中的args,bipush 100意思是先往栈中放入100,然后istore_1将100保存在本地变量1,然后将200保存在本地变量2,然后将常量值2入栈,存在本地变量3的位置,getstatic #2,获取常量池(demo.txt中的Java版本号下面)中的#2常量(对应的也就是System.out.PrintStream),然后将变量表中的位置1的值压入栈,位置2也压入栈,执行加法操作(注意,这里执行加法操作之后,栈中就剩下最后的结果300了,),invokevirtual(查询指令表,“运行时方法绑定调用方法”),调用静态方法,JVM会根据这个方法描述,创建新的栈帧,方法的参数从操作数栈中弹出,压入虚拟机栈,然后虚拟机会开始执行虚拟机栈最上面的栈帧。执行完毕后,在执行main方法对应的栈帧。

最后输出完之后,return,main方法也执行结束。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
Vander1991~ 发布了2 篇原创文章 · 获赞 0 · 访问量 23 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: