1.jvm的位置
jvm调优99%是方法区和堆,主要是堆
2.jvm的体系结构
3.类加载器
作用:加载class文件
4.双亲委派机制
APP----EXC----BOOT
- 类加载器收到类加载的请求
- 将这个请求向上委托给父类加载器去完成,一直向上委托,知道启动类加载器
- 启动类加载器检查是否能够加载当前和这个类,能够加载就结束,使用当前的加载器,否则,抛出异常,通知子加载器进行加载
- 重复第三步
5.沙箱安全机制
远程代码就是你服务器的代码,想获取你本地的资源,不安全,做了个沙箱安全机制,需要给权限
6、Native、方法区
凡是带了native关键字的,说明java的作用范围达不到了,会区调用底层c语言库。
凡是带了native关键字的,会进入本地方法栈
调用本地接口:JNI
JNI 作用:扩展java的使用,融合别的语言为java所用,他在内存区域中专门开辟了一块标记区域:Native Method Stack,登记native方法在最终执行的时候去加载本地方法库方法,通过jni
本地方法接口(JNI)Java Native Interface
本地方法库:
private native void start0();
7.方法区
静态变量,常量,类信息(构造方法,接口定义)、运行时的常量池存在方法区中,但是实例变量存在堆内存中。和方法区无关。
类加载的过程:
- new一个类的时候,现在方法区有一个类模板
- 类模板完了,方法区还有个常量池
- 引用 在栈内存
- 真实的对象在堆内存
- 引用指向堆内存真实的地址
8.栈
数据结构
程序=数据结构+算法
程序=框架+业务逻辑
栈:先进后出,后进先出
队列:先进先出
为什么main先执行,最后结束!
栈:占内存,主管程序的运行,生命周期与线程同步;
线程结束,栈内存释放,对于栈来说,不存在垃圾回收的问题
一旦线程over,栈就结束了
栈:8大基本类型+对象引用+实例的方法
栈运行原理:栈帧
9.堆(heap)
一个jvm只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般会把什么保存到堆中?
答:类的实例,方法,变量,保存我们所有引用类型的真实对象
堆内存还要分为三个区域:
- 新生去
- 养老去
- 永久区
1.GC 垃圾回收主要是在伊甸园区和养老区~
2.假设内存满了,OOM ,堆内存不够!
3.在JDK 8以后,永久存储区改了个名字(元空间)
10.新生区、养老区
类:诞生,成长,死亡
新生区:
- 伊甸园:所有的对象都是在这new出来的
- 幸存者区
- 幸存者0
- 幸存者1
真理:经过研究,99%的对象都是临时对象。
11.永久区
永久区常驻内存的,用来存放JDK自身携带的class对象,interface元数据,存储的是Java运行时的一些环境或类信息这个区域不存在垃圾回收!关闭虚拟机就会释放这个区域的内存
OOM出现条件:一个启动器,加载了大量的第三方jar包、Tomcat部署了太多应用,大量动态生成的反射类,直到内存满。
- jdk1.6:永久代,常量池实在方法区中
- jdk1.7:永久代,但是慢慢的退化了,去永久代,常量池在堆中
- jdk1.8之后:无永久代,常量池在元空间
默认情况下:分配的总内存是电脑内存的1/4,初始内存的1/16
idea配置vm配置
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
12.GC:
1.垃圾回收机制
垃圾回收的区域只有在堆里面(方法区在堆里面)
2.垃圾回收=GC
jvm在进行垃圾回收时,并不是对这三个区域统一回收。大部分时候,回收都是新生代
新生区
幸存区
老年区
GC俩种类:
轻GC:轻GC只针对新生代和偶尔走一下幸存区
重GC(全局):全部清完
GC算法:
引用计数法
复制算法:谁空谁是to,当一个对象经历了15GC,他就会进入养老区
标记清除法:对没有标记的清楚。
3.总结
内存效率:复制算法>标记清楚算法>标记压缩算法(时间复杂度)
内存整齐度:复制算法=标记清楚算法>标记清除算法
内存利用率:标记压缩算法=标记清楚算法>复制算法
年轻代:存活率低,复制算法
老年代:存活率高,区域大。标记清除+标记压缩混合实现