Class文件
Class文件包含Java程序执行的字节码。数据严格按照格式紧凑排列在class文件中的二进制流,中间无任何分隔符。文件开头有一个0xcafebabe(十六进制)的特殊标志。
文件中包含版本、访问标志、常量池、当前类、超级类、接口、字段、方法、属性。
文件是有复杂的格式,专门是给JVM读里面的内容,人类阅读可以借助工具查看。通过javap指令可以查看class文件内容。
JVM执行引擎执行的是源码编译过后的指令码。class文件中存储着这些指令码,javap翻译出来的是对应的操作符。
JVM运行时数据区
JVM运行时数据区分为线程共享部分和线程独占部分。线程共享是所有线程都能访问这块内存区域,随虚拟机和GC而创建和销毁。线程独占是每个线程都会有它独立的区域,随线程的生命周期创建和销毁。线程共享部分继续分为方法区和堆内存。线程独占部分继续分为虚拟机栈、本地方法栈和程序计数器。
方法区
方法区是JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据。在虚拟机规范中这是一个逻辑区划,具体实现根据不同虚拟机来实现。如:oracle的Hotspot的方法区在java7是放在永久代,在java8是放在元数据空间,并通过GC机制对这个区域进行管理。
堆内存
堆内存可以细分为新生代、老年代。新生代又分为Eden区、From survivor区、To survivor区。
堆内存在JVM启动时就会创建,用来存放对象的实例。如果堆内存满了,就会抛出OutOfMemroyError。
虚拟机栈
虚拟机栈,每个线程在这个空间有一个私有的空间。虚拟机栈由多个栈帧组成。一个线程会执行一个或者多个方法,一个方法对应一个栈帧。栈帧的内容包含局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大是1M,超过会报StackOverflowError。
程序计数器
程序计数器用来记录当前线程执行的字节码的位置,存储的是字节码的指令地址,如果执行的是native方法,则计数器值为空。
每个线程在此空间有一个私有的空间,占用的内存很少。
CPU同一时间只会执行一条线程的指令,JVM多线程会轮流切换并分配CPU执行时间的方式。线程切换后需要通过程序计数器,来回复正确的执行位置。
程序的完整运行过程
- JVM把类信息、常量等信息加载到方法区。
- JVM创建线程来执行代码。在虚拟机栈和程序计数器内存区域创建线程的独占空间。
- JVM从main方法开始执行其中的指令码。使用虚拟机栈中的局部变量表、操作数栈等内存空间执行指令操作。