JVM的基本知识
0.JVM的预知知识
- JVM是用c语言写的,在操作系统之上。
- java在jre里面运行。
1.JVM的位置
2.JVM的体系结构
- 文件一开始为.java文件,用过javac编译为Class File(.class字节码文件),再到达类加载器Class Loader.
- 栈Stack、本地方法栈、程序计数器里面不可能有垃圾,有垃圾的话,程序就会报错了.
- 方法区属于特殊的堆,所谓的JVM调优就是在调堆和方法区,大部分在调堆.
- 执行引擎包含:解释器、编译器、垃圾回收器.
3.类加载器
- 作用:加载Class文件
- 四类加载器:
- 虚拟机自带的加载器
- 启动类(根)加载器(Bootstrap):负责java平台核心库,用来装载核心类库(该加载器无法直接获取),用c写的。
- 扩展类加载器(Extension)
- 应用程序加载器(App)
public class Car {
public int age;
public static void main(String[] args) {
//类是模板,对象是具体的
Car car1 = new Car();
Class<? extends Car> aClass1 = car1.getClass();
ClassLoader classLoader = aClass1.getClassLoader();
System.out.println(classLoader); //AppClassLoader
System.out.println(classLoader.getParent()); //ExtClassLoader
System.out.println(classLoader.getParent().getParent()); //null
// 为null的可能: 1.不存在 2.java程序获取不到
}
}
4.双亲委派机制
- 定义:双亲委派机制是当类加载器需要加载某一个.class字节码文件时,则首先会把这个任务委托给他的上级类加载器,递归这个操作,如果上级没有加载该.class文件,自己才会去加载这个.class。
- 作用:
- 防止加载同一个.class。通过委托去询问上级是否已经加载过该.class,如果加载过了,则不需要重新加载。保证了数据安全。
- 保证核心.class不被篡改。通过委托的方式,保证核心.class不被篡改,即使被篡改也不会被加载,即使被加载也不会是同一个class对象,因为不同的加载器加载同一个.class也不是同一个Class对象。这样则保证了Class的执行安全。
- 这段代码执行不了。
- 原因是:
- 类加载器收到类记载的请求。
- 将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器(Boot)。
- 启动类加载器检查是否能够加载当前这个类,能加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载。
- 重复步骤3。
- 都找不到就报出Class Not Found错误。
5.沙箱安全机制
- 沙箱:一个限制程序运行的环境。
- 沙箱机制:将java代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破话。
- 主要限制系统资源访问,例如 CPU、内存、文件系统、网络。
组成沙箱的基本组件:
- 字节码校验器(bytecode verifier):确保java类文件遵循java语言规范。但并不是所有的类文件都会经过字节码校验,比如核心类。
- 类装载器(class loader): 类装载器在三个方面对java沙箱起作用
- 防止恶意代码去干涉善意的代码。 (双亲委派机制)
- 守护了被信任的类库边界。(双亲委派机制)
- 将代码归入保护域,确定了代码可以进行哪些操作。(沙箱安全机制)
6.Native
- 凡是带了native关键字的,说明java的作用范围达不到了,会去调用底层c语言的库,进入本地方法栈,调用本地方法本地接口( JNI(JNI作用为:扩展java的使用,融合不同的编程语言为java所用,最初想融合c、c++。) )。
7.PC寄存器
程序计数器:Program Counter Register
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向像一条指令的地址,也即将要执行的指令代码),在执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
8.方法区
Method Area 方法区
-
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间;
-
静态变量(static)、常量(final)、类信息(Class)(构造方法、接口定义)、运行时的常量池存在方法区中,但是 实例变量存在堆内存中,和方法区无关。
9.栈
- 主要存储 8大基本类型 + 对象引用 + 实例方法,栈不可能存在垃圾
- 栈运行原理:栈帧
- 栈满了就会出现StackOverflowError
- 问题:
- 栈怎么存东西
- 画一个对象实例化的过程在内存中
10.三种JVM
- Sun公司 HotSpot (在cmd中 Java -version看当前用哪个虚拟机)
- BEA
- IBM
11.堆
-
Heap,一个JVM只有一个堆内存,堆内存的大小是可以调节的。
-
类加载器读取类文件之后,会把类实例、方法、常量、变量放堆中,保存我们所有引用类型的真实对象。
-
堆内存分为三个区域
-
新生区(伊甸(dian)园区)
-
养老区
-
永久区(在JDK8以后,永久区改名字为元空间,本质没什么区别)
- 元空间在逻辑上存在,物理上不存在。
-
-
GC垃圾回收主要在伊甸园区和养老区,垃圾回收分为轻量级(针对新生区来的)和重量级。
-
假设内存满了,就会报OOM错误,堆内存不够(java.lang.OutOfMemoryError: Java heap space)。
- 报OOM时:
- 尝试扩大堆内存看结果。
- 分析内存,看一下哪个地方出现了问题(专业工具)
import java.util.Random; public class oom { public static void main(String[] args) { String str = "dongdongdong"; //在java中,String可以无限长,但堆内存会满 while (true){ str += str + new Random().nextInt(888888888); } } }
- 报OOM时:
12.新生区,老年区
- 新生区:
- 类诞生和成长的地方、甚至死亡。
- 分为伊甸园区和幸存者0区、幸存者1区。
- 所有的对象都是在伊甸园区new出来的。
- 老年区
13.永久区
这个区域是常驻内存的,用来存放JDK自身携带的Class对象、interface元数据,存储的是java运行时的一些环境,这个区域不存在垃圾回收,当关闭虚拟机就会释放这个区域的内存。
14.堆内存调优
15.GC:垃圾回收器
-
GC的作用区域:
-
GC题目:
- JVM的内存模型和分区
- 堆里面的Eden、from、to、老年区,各有什么特点?
- GC的算法有哪些? 标记清除法、标记压缩、复制算法、引用计数器
- 轻GC和重GC分别在什么时候发生?
16.JMM
-
Java Memory Model:java内存模型
-
作用:缓存一致性协议,用于定义数据读写的规则(是规则就该遵守)。
JMM定义了线程工作内存和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory)。
解决共享对象可见性这个问题:voliate
MM
-
Java Memory Model:java内存模型
-
作用:缓存一致性协议,用于定义数据读写的规则(是规则就该遵守)。
JMM定义了线程工作内存和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory)。
[外链图片转存中…(img-mer25vCy-1635465740926)]
解决共享对象可见性这个问题:voliate