1 程序计数器 线程私有,记录线程所执行的字节码行号指示器。
2 虚拟机栈 描述Java方法执行内存模型 , 进入一个方法创建栈帧。
3 Java堆 存放对象实例
4 方法区:编译后的代码数据,包括加载 的类信息,常量,静态变量。
5 常量池 :class文件常量池方法区一部分存放编译器生成的字面量和符号引用,加载时放入虚拟机的运行时常量池中
6 对像创建 : 1 类是否已经加载 2 为对象分配内存 类加载后,对象所需内存确定 , 内存空间初始化0,3 设置对象头部信息 (对象所属类,哈希等) 4 根据程序员意愿,执行init方法,为对象设置初值。
7 对象布局: 对象头(1 对象运行时数据 2 类型指针 数组还有数组长度), 实例数据信息 , 对其填充
8 对象访问定位 1 句柄 (对象数据指针 对象类型指针) 好处,reference存稳定句柄值,对象变化只改变句柄中对象数据指针, 2 直接 对象地址,好处 访问块。
9分析是内存溢出还是内存泄漏,如果内存泄漏,找出泄漏对象到GC roots的引用链,看为什么对象没有回收, 如果是内存溢出,看虚拟机堆是不是太小。看某些对象生命周期是否过长,尝试减少运行期间内存消耗。
10 哪些内存需要回收。Java堆,方法区
11 什么时候需要回收 对象死
1 引用计数算法:每一个地方引用对象,计数器加1 , 很难解决对象之间相互循环引用问题。
2 可达性分析 “GC Root” 对象为起点,从起点向下搜,所走过路径为引用链,当对象到“GC Root” 没有引用链时,对象不可达。
12 生存还是死亡 不可达对象, 检测对象是否有必要执行finalize方法,如果没有覆盖finalize方法或方法已经被虚拟机调用过,会直接回收,如果有必要执行方法,在这个方法中对象有可能存活。
public class JDBCTest{ public static JDBCTest j = null; public void isAlive() { System.out.println(" i am alive"); } @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub super.finalize(); System.out.println("finalize exet"); j = this; } public static void main(String[] args) throws Exception { j = new JDBCTest(); j = null; System.gc(); Thread.sleep(500); if (j != null) { j.isAlive(); } else { System.out.println("j dead"); } j = new JDBCTest(); j = null; System.gc(); Thread.sleep(500); if (j != null) { j.isAlive(); } else { System.out.println("j dead"); } } }
13 回收方法区 1 废弃常量,无用类 1 类实例被回收 2 类classloader被回收 3 Class对象没有被引用
14 垃圾回收算法
1 标记 -清除 缺点 标记,清除效率不高 产生大量不连续碎片
2复制 分为大的eden和小的survivor 只用Eden ,垃圾回收时将存活对象放入survivor ,并清除Eden
3 标记 -- 整理 对垃圾回收后大部分对象都会存活使用 和标记-清除不同的是,让存活对象像一边移动,清除边界外内存。
4 分代收集 根据对象存活周期不同,新生代 ,每次垃圾收集都有大量对象死,使用复制算法 老年代 对象存活率高,标记清理或标记整理
15 hotSpot算法实现
1 枚举根节点(全局性引用,常量或静态属性 与执行上下文 栈帧本地变量表)stop the world 枚举跟节点时,必须停止所有线程,否则枚举不准确 ,编译类后使用oopMap数据结构记录哪个地方有引用,加快枚举跟节点速度
2 安全点 在安全点停下来GC, 是否有让程序长时间执行的特征 方法调用 ,循环跳转 异常跳转
如和在GC发生时让线程在安全点停下,1 抢占式 中断所有线程,如果发现有线程没有到安全点,线程跑到安全点 2 主动中断 在安全点轮询,如果需要GC,把自己中断。
3 如果线程处于sleep或阻塞,线程无法相应jvm中断请求,走不到安全点,需要安全区域:在这段代码片段中,引用关系不发生变化,任意地方开始GC安全。在线程要离开安全取时,检测是否完成枚举跟节点。
serial 新生代 垃圾收集时必须停止所有线程工作。并且只有一条线程垃圾回收 client模式默认
ParNew serial 多线程版本 , 可以有多条线程垃圾回收 server模式默认
parallel scavenge 和ParNew 很相似 , 多条线程垃圾回收 , 和上一个关注停顿时间不同,主要关注吞吐量(用户代码运行时间/总运行时间),适合和用户交互少的后台代码执行。可以直接设置吞吐量和最大停顿时间。
老年代
serial old serial老年代版本,单线程收集, 标记整理, client模式
Paraller old 是parallel scavenge老年代版本 多线程收集 在注重吞吐量和CPU资源敏感场合,优先Paraller old ,parallel scavenge组合
cms (concurrent mark sweep) 以获取最短回收停顿为目标,标记清除算法,
4个步骤 初始,重新 stop the world , 初始标记只标记GC Root直接关联对象,速度很快 并发标记 经行GC Roots Tracing过程,重写标记修正并发标记期间的修改,
缺点1 cms对CPU资源敏感 2 无法处理浮动垃圾 可能出现concurrent mode failure 失败导致另一次full gc,由于cms并发清理阶段用户线程还在运行着,伴随程序运行还有垃圾产生,垃圾出现标记过程后,cms无法在当次处理他们,只好下次gc,这部分垃圾为浮动垃圾 3 空间碎片
G1
并行 :多条垃圾回收线程一起执行
并发 :垃圾回收,用户程序一起执行
内存分配与回收策略