原文:https://nuyoah-xlh.github.io/2022/01/07/%E6%B5%85%E5%B0%9DJVM/
JVM的位置
JVM体系结构
类加载器
**作用:**加载class文件。new Student()时,引用放在栈中,而实例放在堆中。
过程(双亲委派机制 ):
- 类加载器收到类加载的请求;
- 将这个请求向上委托给父类加载器去完成,一直向上委托,直到启动类加载器;
- 启动类加载器检查是否能加载当前类,如果能,结束;如果不能,则抛出异常,通知子类加载器加载;
- 重复步骤三,直到结束。
加载器:(上方是下方的父类)
- 启动类(根)加载器
- 扩展类加载器
- 应用程序加载器
- 自定义类加载器
注:native修饰的方法为调用本地方法栈,意为Java无法处理,调用C++方法-本地方法。
沙箱安全机制
Java安全模型的核心就是Java沙箱(sandbox),什么是沙箱?沙箱是一个限制程序运行的环境。沙箱机制就是将 Java 代码限定在虚拟机(JVM)特定的运行范围中,并且严格限制代码对本地系统资源访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问,那系统资源包括什么?——CPU、内存、文件系统、网络
。不同级别的沙箱对这些资源访问的限制也可以不一样。
所有的Java程序运行都可以指定沙箱,可以定制安全策略。
Native&&方法区
- 凡是带了native的关键字的,说明java的作用范围达不到了,回去调用底层c/c++语言的库。
- 会进入本地方法栈,调用本地方法JNI
- JNI:扩展java的使用,融合不同的编程语言为java所用
- 在内存区域中,专门开辟了一块内存区域:native method stack,用来登记native方法
- 在最终执行的时候,加载本地方法库中的方法调用JNI
- 静态变量(static)、常量(final)、类信息(Class)、运行时常量(常量池)存在方法区,但实例变量存在堆内存中
堆
- 一个jvm只有一个堆内存,大小可调节
- 细分三个区域:
- 新生区(伊甸园区)
- 养老区
- 永久区(元空间)
- GC垃圾回收主要在前两个区
- OOM:堆内存不够
新生区
- 类:诞生和成长、甚至死亡的地方;
- 伊甸园:所有的对象都是在这里new出来的;
- 幸存者区(0,1),暂时还未淘汰
- 使用的是浅gc
养老区
- 多次淘汰后仍存在,则放到养老区
- 使用的是重gc
永久区(元空间)
- 常量池在元空间;
- 常驻内存,存放jdk自身的Class对象,interface元数据;
- 此区域不存在垃圾回收
- 在堆中,逻辑上存在,物理上不存在,又称“非堆”
OOM
- 分析OOM原因的工具:JProfiler
vm-options:
- -Xms:设置初始内存分配大小
- -Xms:设置最大可分配内存
- -XX:+PrintGCDetails:打印GC垃圾回收信息
- -XX:+HeapDumpOnOutOfMemoryError:当抛出OutOfMemoryError异常时,产生dump文件,OutOfMemoryError可修改
- 例:
-Xms1m -Xms8m -XX:+HeapDumpOnOutOfMemoryError
GC算法
引用计数法
- 计算每个对象的引用次数以决定GC
复制算法
- 两个幸存区,一个为from区,一个为to区,哪个为空则哪个为to区。from和to对象复制交换,以便每次gc,将Eden区幸存的对象放到空的to区中,同时from的对象也放到to区中
- 当一个对象经历了15次gc仍存活,则放到老年区
- -XX:MaxTenuringThreshold=15
标记压缩清除算法(结合可达性算法)
- 缺点:两次扫描,浪费时间,会产生内存碎片
- 优点:不需要额外内存空间
标记压缩算法
总结
内存效率:复制算法->标记清除算法->标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法->标记清除算法
内存利用率:标记压缩算法=标记清除算法->复制算法
- 分代收集算法
- 年轻代:
- 存活率低
- 复制算法
- 老年代:
- 区域大、存活率高
- 标记清除+标记压缩混合
- 年轻代: