JVM
1. JVM体系结构
- “对象的引用”在栈里面
- 真正对象的“数据”在堆里面
2.类加载器及双亲委派机制
类加载器
作用:加载class文件
类是模板,对象是具体的
public class Test {
public static void main(String[] args) {
//类是模板,对象是具体的
Class testClass = Test.class;
}
}
test1,test2,test3 三个对象都是类模板new出来的,通过第一次输出可以知道,三个对象是不一样的。
但是他们getClass后输出的结果就是一样的,因为getClass得到的是类的模板
加载器的分类
- 虚拟机自带的加载器
- 启动类(根)加载器 BOOT
- 扩展类加载器 EXC
- 应用程序(系统类)加载器 APP
双亲委派机制
APP ---> EXC ---> BOOT
BOOT中不存在 ---> EXC中不存在 ---> APP(当前应用)
双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。
-
1、当 AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
-
2、当 ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader```去完成。
-
3、如果 BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class),会使用 ExtClassLoader来尝试加载;
-
4、若ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException。
举个例子
我们模拟Java中lang包下的String类,它一直会询问自己的父加载器有没有这个类,恰好BOOT中有这个类,但是其中没有main方法,就会报错。
假如是换一个名字,根加载器中没有这个Student类,那么它就能正常加载成功。
3、native关键字
凡是被native修饰的,说明java的作用范围达不到了,会去调用c,c++语言的库!
以“start0();”方法为例
- 调用被native关键字修饰的方法,会进入本地方法栈
- 然后会调用本地方法的本地方法接口(JNI)
- JNI的作用:扩展java的使用,融合不同的编程语言为java所用!最初是c/c++
- java诞生的使用,c/c++很流行,想要立足,就必须要用c/c++的程序
- 因此,它在内存区域中专门开辟了一块标记区域Native Method Stack,来登记native方法
- 在最终执行的时候,通过JNI(本地方法接口)来加载本地方法库中的方法
- 平常用不到这类的方法,该方法多操控硬件资源
4、PC寄存器
程序计数器:Program Counter Register(PC计数器或者指令计数器更贴切):
-每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计
如果正在执行的是本地(Native)方法,这个计数器值则应为空(Undefined)
5、方法区
方法区 Method Area:
- 又被称为静态区,它跟堆一样被所有线程共享
- 它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据
- 方法区中包含的都是整个程序中永远唯一的元素,如:class、static变量。
6、栈
栈(先进后出):也叫栈内存,主管程序的运行,它的生命周期和线程同步;线程结束,栈内存也就释放了;对于栈来说,不存在垃圾回收问题;一旦线程结束,栈就“Over”;
- 每个线程都包含一个栈区,栈中只保存基本数据类型的值和对象以及基础数据的引用。(8大基本类型+对象引用+实例的方法)
- 每个栈中的数据(基本数据类型和对象的引用)都是私有的,其它栈是无法进行访问的。
- 栈分为三个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
栈运行原理:栈帧,程序正在执行的方法一定在栈的顶部
什么是栈溢出:(StackOverflowError)
package com.my.test;
//理解什么叫栈溢出
//为什么main()方法先执行后结束
public class Test03 {
public static void main(String[] args) {
Test03 test03 = new Test03();
test03.a();
}
public void a(){
b();
};
public void b(){
a();
};
}
7、三种JVM
- sun公司的HotSpot(Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode))
- Oracle公司的 JRockit
- IBM J9 VM
8、堆(Heap)
Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java世界里“几乎”所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的内存区域,因此它也被称作“GC堆”。
一个JVM只有一个堆内存,堆内存的大小是可以调节的。
堆内存中细分为三个领域:
- 新生区(伊甸区)young/new
- 养老区old
-
永久区perm
GC垃圾回收:主要在伊甸园区和养老区
“OOM”:内存满了,堆内存不够
JDK8以后永久存储区更名为“元空间”
新生区
- 类:诞生和成长以及死亡的地方
- 伊甸园区:所有的对象都是由伊甸园区new出来的
永久区
- 概念:
这个区域常驻内存,用来存放JDK自身携带的Class对象、interface元数据、存储的是java运行时的一些环境或者类信息
这个区域不存在垃圾回收;除非关闭虚拟机才会释放这个区域的内存
共有 0 条评论