1.JVM(Java Virtual Machine):Java虚拟机是在计算机系统上用软件实现的一台假想机;Java程序在运行的时候,JVM把Java字节码解析成机器码。
1.1JVM有自己完善的硬件架构,例如:处理器、堆栈、寄存器等,还具有相应的指令系统,它屏蔽了具体操作系统平台相关信息。每当一个Java程序运行时,都会有一个对应的JVM实例,只有当程序运行结束后,这个JVM才会退出。JVM实例通过**main()**方法来启动一个Java程序。
2.JDK(Java Development Kit):JDK是用于开发Java程序的最小的环境。我们把Java程序设计语言,Java虚拟机,Java API类库这三部分统称为JDK
3.JRE(JavaRuntime Enviroment):JRE是支持Java程序运行的标准环境。我们可以把Java API类库中的Java SE API子集和JVM这两部分统称为JRE
4.Java API(Application Program Interface) :应用程序接口;它提供了许多有用的接口,这些接口也是java语言编写的,并且运行在JVM上。
Java平台逻辑结果:
JVM在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域(程序计数器,虚拟机栈,本地方法栈,堆,方法区)。
内存区域为线程私有:程序计数器,虚拟机栈,本地方法栈;
内存区域为线程共享:堆,方法区。
把内存区域划分为线程共享和线程私有的原因:JVM在 初始运行的时候 都会分配好 方法区 和 堆,当JVM每遇到 一个线程 的时候,就会为其分配一个 程序计数器,虚拟机栈,堆,当线程终止时,这个三个内存空间将会被释放。简单来说就是:线程私有的三个区域的生命周期与其所属的 线程 相同,而 线程共享 的区域的生命周期和 Java程序 相同,所以这也是 系统垃圾回收场所 只发生在 线程共享 的区域(实际上对于大部分的虚拟机来说只发生在 堆 上)。
局部变量表:表所需的内存空间在 编译期间 完成分配, 局部变量表存放了编译期可知的各种基本的 数据类型(boolean,byte,char,short,int ,long,double)、对象的引用(reference)类型(注意:对象的引用不等同于对象本身,根据不同的虚拟机,可能是一个指向对象起始地址的引用指针,也可能是一个代表对象的句柄或者其他与对象相关的位置)、returnAdress(指向下一条字节码指令的地址)。
注:Java栈 (虚拟机栈+本地方法栈):线程私有,Java栈由一系列的帧组成因此Java栈也称为帧栈;帧中保存着一个方法的局部变量,操作数栈,常量池指针;每一次方法调用时创建一个帧,并压入栈。
小对象(一般为几十个bytes)
直接分配在栈上,可以自动回收,减轻GC压力
大对象或者逃逸对象无法在栈上分配
运行时常量池: (Runtime Constant Pool):是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种 字面量 和 符号引用,这部分的内容将在类加载后进入方法区的运行时常量池中存放。
示例代码:
package dong.test;
public class Test {
private String a = "aa";
public boolean methodB(){
String b = "bb";
final String c = "cc";
return false;
}
public static void main(){
}
}
上面代码中变量 a,b,c 分别在内存的堆区、栈区、栈区;其中a为全局变量(线程共享),b、c为局部变量。
小结:
1.我们所了解的Java程序工作过程是一个Java源程序文件,会被编译为字节码文件(.class文件)。每个Java程序都需要运行在自己的JVM上,然后告知JVM程序的运行入口,再被JVM通过 字节码解析器 加载运行。
2.JVM启动,我们的.java代码会编译成.class文件,然后被类加载器 加载 进入jvm内存,类中对象Object会加载到方法区中,而创建了Object类的类对象(注意是类对象,不是new出来的对象,而是类的类型对象。每一个类只有一个class对象,作为方法区的数据结构的接口)加载到堆中。
3.jvm在创建对象前,会先检查 类 是否加载。寻找类对应的class对象,如果加载好,则为对象分配内存,初始化 也就是new Object()。
4.:栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中的对象不一定会销毁。因为可能会有其他变量也指向了和这个变量,直到没有栈中没有变量指向堆中的对象是,它才销毁,而且不是马上赶销毁,要等到垃圾回收扫描时才可以被销毁。
5.类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量存储在堆中的对象中);而类的方法却是该类的所有的对象共享的,当对象使用方法的时候才会将方法压入栈中,当方法不被调用时则是不占用内存的。
注:部分内容摘抄于该博客!
补充:1.在JDK1.8前方法区属于堆中永久区(PremSize)的一部分,但是在JDK1.8中舍去了永久区取而代之的是元空间(MetaSpace),在元空间中存储信息使用的是个更大的物理内存,这样一来在元空间发生的GC的次数也会相应的减少。
同样的JVM调优参数上:由PremGenSize和MaxPrenGenSize 对应这 MetaspaceSize和MaxMetaSpaceSize;
补充2:本地方法接口,是用C或者C++的实现的操作系统相关方法。即JVM通过本地方法接口可以和底层的操作系统打交道。
demo:
C:/Program Files/Java/jdk1.8.0_161/src.zip!/java/lang/ClassLoader.java:23
private native final Class<?> findLoadedClass0(String name);
补充3:JDK6和JDK6+版本下的String intern()方法的是说明:链接地址