JVM学习笔记
JVM的位置
运行在操作系统上的(win,linux,mac)
堆里面有垃圾,栈一定不会有垃圾
jvm调优,基本都是在方法区和堆。
类加载器
作用:加载class文件~
- 虚拟机自带的加载器
- 扩展类加载器
- 应用程序加载器
- 启动类加载器
双亲委派机制
APP–>EXC–>BOOT(最终执行)
一层一层的找,先是写的 文件里,然后是jre包里,最后是rt包里。因为根目录里有String,所以最后执行的是跟加载器里的。
java沙箱安全机制
栈:数据结构
先进后出,一个桶类型。
队列:先进先出;(FIFO)
方法相互调用,会产生栈溢出报错
public void a(){
b();
}
public void b(){
}
主管程序的运行,生命周期和线程同步;
线程结束,栈内存也就释放了;对于栈来说,不存在垃圾回收问题。
一旦线程结束,栈就over;
栈里面可以放 8大基本类型数据、引用对象、实例的方法;
栈运行原理:栈帧
堆
heap 一个jvm只能有一个堆,而且堆是可以根据参数随意调整大小
类加载器读取了类文件后,一般会把什么东西放到堆中? 类、常量、变量、方法~,保存所有引用类型的真实对象。
堆内存中细分三个区域:
- 新生区 young
- 养老区 old
- 永久区 perm
GC回收主要是在伊甸园区和养老区
内存满了就会报OOM错误,就是堆内存不够
新生区
- 类:诞生、生存或者死亡的地方
- 伊甸园:所有的对象都是在伊甸园区new出来的
- 幸存者(0/1):
常量池是在方法区里的
元空间 :逻辑上存在,但是物理上不存在
GC
GC的算法有哪些:
- 标记清除法
- 标记压缩
- 复制算法
- 引用计数器
引用计数法
引用计数法就是给每一个对象加上一个计数器,使用一次就被加一,这样,当对象一段时间被使用次数为0时候,那么就将它作为垃圾回收。
缺点:因为在使用时候,需要给每一个对象都要加一个计数器,这样的话,就会使得空间占用成本较大,因为计数器也占内存,而且,如果一个对象在循环中,被大量使用,计数器也被反复调用,这样的话,也会使内存增高。
复制算法
幸存区,谁是空是谁to区。 每次GC都会将伊甸园区活的对象移动到幸存区中:一旦eden园区被GC后,就会是空的。如果当to区和from都有值,这种情况,需要保证to区是0,所以,这个时候就需要把其中一个区的值给到另外一个区。这就是复制算法。。当一个对象经历了15次的GC都还没有死,就会进入到养老区。
优点:没有内存碎片
缺点:浪费了内存空间,永远有一个to区
复制算法最佳使用场景:对象存活度较低的时候,新生区
标记清除算法
第一遍扫描,对活着的对象进行标记。
第二遍扫描,对未标记的对象进行清除
缺点:俩次扫描严重浪费时间,会产生内存碎片
优点:不需要额外的空间
标记压缩
在优化标记清除。
在上面清除之后,再一次扫描,将标记的对象像一段存活,多了一个移动。
总结
内存效率:复制算法>标记清除算法>标记压缩算法
内存整齐度:复制算法=标记清除>标记压缩
内存利用率:标记压缩=标记清除> 复制算法
没有最优的算法,只有最合适的
GC:分代收集算法:
- 年轻代:存活率低,复制算法
- 老年代:存活率高,区域大,标记清除(内存碎片不是很多的时候)和标记压缩混合实现
标记清除算法>标记压缩算法
内存整齐度:复制算法=标记清除>标记压缩
内存利用率:标记压缩=标记清除> 复制算法
没有最优的算法,只有最合适的
GC:分代收集算法:
- 年轻代:存活率低,复制算法
- 老年代:存活率高,区域大,标记清除(内存碎片不是很多的时候)和标记压缩混合实现