- 内存运行模型
- 常量优先被jvm加载;
- 方法区:关于类的信息都存在方法区,是共享的;
- 堆:存储对象和数组,也是共享;
-
- 程序计数器:存储程序运行到哪个位置;
- 本地方法栈:是Native;
- 栈区:每个方法运行的过程,运行完压栈
- 垃圾回收
- 垃圾回收器回收的是堆里的;
- 回收对程序没有意义的对象;
- 引用计数算法:
- 引用计数算法是在对象中加入一个计数器,当对象被引用,计数器+1,当引用失效,计数器-1,当计数器的值编程为0,就是没有任何一个变量来引用这个对象,那么这个对象就是垃圾;
- 缺点:这种算法实现简单,效率高,但是有一个严重的问题会导致内存泄漏,那就是对象之间循环引用,比如说A对象持有B对象的引用,B对象持有A对象的引用,那么A和B的计数器值永远>=1,也就是说这两个对象永远不会被回收,这是一堆垃圾。
- 可达性分析算法:
- Java中定义了一些起始点,称为GC Root(GC是守护线程),当有对象引用它的时候,就把对象挂载在它下面,形成一个树状结构,当一个对象处于一个这样的树里时,就认为此对象是可达的,反之是不可达;
- GCROOT包含什么:
- 虚拟机栈中正在引用的对象;
- 本地方法栈中正在使用的对象;
- 类中静态属性引用的对象;
- 常量应用的对象;
- 垃圾收集算法:
- 标记清除法:
- 一个是效率问题,标记和清除过程的效率都不高;
- 另外一个是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
- 标记复制:
- 空间浪费,同一时间只能用一半的空间;
- 标记整理:标记出正在使用的,把这些正在使用的整理到一边;
- 分代收集算法:
- 刚new出来的放到新生代中;
- 当一个对象经历多次GC后,还是可达的,说明jvm觉得这个对象比较重要不会轻易被回收,就把这个对象加入到老年代区域;
- 永久代: 方法区
- 新生的对象,先存放在伊甸园区,伊甸园区存满了和幸存区的工作空间S0,一起标记复制,复制到幸存区另一个区间S1,伊甸园和S0区被清空;下一GC就是将伊甸园区和S1区存活的对象放到S0区,S1和S0依次切换;
- 伊甸园区满了触发Minor GC,如果Minor GC15次新生代,依然存活就放到老年代里面;
- 老年代满了触发Full GC;
- 老年代就是方法区;
- 空出大的空间:老年代标记整理法,新生代标记复制法
- System.gc()是fullGC,fullGC发生在发生在老年代和整个堆的垃圾收集;
- 加载:通过类加载器加载,数组比较特殊,扫描到需要数组才开始创建;
- 加载是jvm将程序中要使用的类以流的形式加载到内存中;
- 符号引用:变量名,方法名,类名;
- 直接引用:内存地址;
- 校验格式:
- 文件格式校验:文件的流是否正确:是否是一个class文件;
- 元数据校验:类之间的继承是否规范:是否继承了final类;
- 验证逻辑是否规范:return后是否还有代码,else 前面是否有if;
- 符号引用校验:验证使用变量时是否已经声明或初始化;
- 准备阶段:为类的静态变量分配内存,并将其初始化为[[默认值]],比如:准备默认值,比如基本数据类型的默认值0,0.0,true和false,null还有常量的值;
- 解析阶段:把符号引用转换成直接引用;
- 类的初始化,静态代码块只会执行一遍;
- 给静态属性赋值,调用静态代码块;
- 何时引发类的初始化:
- 直接调用静态属性方法,实例化该类的对象
- 主类会优先初始化,
- 通过反射调用该类的内容;
- 要初始化一个子类,该子类的父类也会引发初始化;
- 被动调用:
- 调用一个类的常量;
- 使用子类名调用父类中的静态变量,不会引发子类的初始化;
- 实例化该类的数组不会引发初始化;
- 不是所有可达的对象都不会被GC掉
- 强引用: Object obj = new Object() obj就是强引用,JVM宁肯抛出OOM异常,也不会GC掉强引用对象
- 软引用: 软引用 引用的对象,当可能抛出OOM的时候,就会将软引用给回收掉
- 弱引用: 比软引用更低,只要发生一次minorGC就可能被回收掉
- 虚引用: 随时都可能被回收
- Serial:单线程,适用于小型运行环境,对新生代进行垃圾收集;
- Parallel:同时收集新生代和老年代;
- CMS:垃圾收集时停顿时间较短,并发收集,内存利用率高,需要更多的CPU;
- G1: 大型内存需求,低停顿、高吞吐量,大量短命对象;
- GC方面:
- 选择合适的垃圾收集器;
- 配置适合存参数:新生代和老年代之间的比例,设置幸存的次数,设置大对象的数值;
- 设置内存大小的参数:
- 开启JIT;
- 选择合适的线程池,避免线程过多的开销,编写更优秀的代码
posted @
2024-01-02 19:41
卡皮巴拉
阅读(
9)
评论()
编辑
收藏
举报