我们都知道,JVM的一个重要特性就是 一处编译 处处运行。那么我们如何理解这个特性呢,接下来就简单分析下JAVA 程序运行的原理。
JAVA代码会编译成class字节码,此字节码文件就是与平台无关的文件,从而在任何平台上,只要有JVM即可加载。
JVM的运行时数据区可以分为线程独占和线程共享两部分:
线程独占:每个线程有自己独立的空间,随着线程生命周期而创建与销毁
线程共享:所有线程都能访问这块内存数据,随着虚拟机或者GC而创建与销毁
其中线程共享部分包括方法去和堆内存:
方法区:JVM用来存储加载类的信息、常量、静态变量以及编译后的代码等数据。是虚拟机规划的逻辑区域,具体实现根据不同。java7方法区放在永久代,java8放在了元数据空间并通过GC机制管理该区域。
堆内存:存放对象的区域。分老年代、新生代(Eden、From Survivor、To Survivor)。JVM启动时创建存放对象实例。垃圾回收器主要就是管理堆内存,如果满了就会OutOfMemoryError。
线程独占部分包括虚拟栈、本地方法栈以及程序计数器:
虚拟栈:每个线程都会在这里创建一个私有空间。每个线程栈有多个栈帧(Stack Frame)组成。一个线程会执行多个方法,每个方法对应一个栈帧。栈帧内容包括:局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大是1M,超过则会抛出StackOverflowError。
本地方法栈:与虚拟机栈功能类似。虚拟机栈是为了虚拟机执行JAVA方法而准备的,本地方法栈是为了虚拟机使用Native本地方法而准备的。
程序计数器:记录当前线程执行字节码的位置,存储的是字节码指令地址,如果执行Native方法则计数器值为空。CPU同一时间只会执行一条线程中的指令。JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器来恢复正确的执行位置。
查看class文件的内容
命令:
//编译
javac XXX.java
//javap查看内容
javap -v XXX.class > XXX.txt
JVM参数: