- Java对象在内存中 三部分 头部信息, 实例数据, 对齐补充
- 句柄访问,直接指针
1.句柄访问是 定义一个指针表 一个包含类型的实例地址,一个包含类型的类型地址
2.直接指针是 直接就能访问实例地址,然后在获取类型信息 - 方法区 类名, 访问修饰符,常量池,字段描述,方法描述
- 不可达意味着该对象可以被回收
- 复制删除 标记整理
JVM模型
- 程序计数器
指向程序执行的字节码地址,如果正在执行的是Native方法,程序计数器为空,不会发生OutofMemoryError - 虚拟机栈
- 局部变量表
- 存放编译可知的基本数据类型以及对象的引用
- double 和 long 占据两个 局部变量空间
- 方法出口
- 动态链接
- 操作栈
- 局部变量表
- 本地方法栈
执行Native方法的栈 - 堆区
- 线程共享
- 存放对象实体
- 分区(方便回收对象)
- 方法区
- class类信息
- 静态变量
- 常量
- 运行时常量
方法区的一部分
垃圾回收器
-
如何判断一个对象该被回收了
- 引用计数器(无法解决对象之间相互引用的问题)
- GCRoot搜索
- 从GCRoots开始向下搜索,搜索过的路径称为引用链,当一个对象跟 GCRoots没有任何引用链时,也就是说该对象不可达,九二一被回收了
-
可以作为GCRoots的对象
- 虚拟机栈(本地变量表中)的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中引用的对象
-
几种引用的区别
- 强引用 Object o = new Object(),只要强引用还在,就不会被回收
- 软引用 如果系统内存不够时,会发生回收
- 弱引用 只能存活到下一次CG前
- 虚引用 没啥用
-
不可达的对象会被标记两次
- 发现没有引用链和GCRoots相连,被标记
- 被标记的对象会放到执行Finalize()的队列中,可能会被引用而不会被回收,但是只能被拯救一次
-
无效的类
- 该类的所有实例都被回收
- 该类的ClassLoader被回收
- 该类的Class对象没有被引用,没有任何地方通过反射生产该类
-
垃圾回收算法
- 标记清除(1.内存碎片2.标记和清除的效率都不高)
- 复制算法
- 标记整理(将所有的对象都移到一端)
-
垃圾回收器
- Serial/Serial Old收集器
- 单线程
- 新生代
- 暂停所有工作线程 Stop the World
- ParNew 收集器
- Serial的多线程版本
- 只能和CMS收集器配合
- 仍然需要暂停所有工作线程STW
- Parallel Scavenge
- 并行多线程收集器(多条收集线程利用多核同时执行)
- 适合于运算量比较大的,没有太多交互的任务
- 为什么叫吞吐量收集器,像CMS停顿时间短,但是可能停顿发生的很频繁,所以吞吐量就小了,这个收集器停顿总时长短,也就是说可能一次发生的停顿时间长,但是停顿的次数少。所以适合不用频繁停顿的。
- 不能与CMS配合,只能和Parallel Old配合
- Parallel Old Serial Old都是标记整理算法, Serial ParNew Paralle Scavenge都是暂停复制算法
- CMS收集器
- 适用于B/S服务器上的一种,因为系统响应短,用户体验好
- 过程
- 初始标记 STW(GCRoots直接关联的对象)
- 并发标记(判断对象是否可达)
- 再次标记STW(新生代可能发生了MinorGC,一些对象不可达)
- 并发清除
- 缺点
- 对CPU敏感,暂用一部分CPU资源
- 如果内存超过一定限额,会触发Full GC
- 会产生很多碎片 标记-清除算法
- G1收集器
- 标记-整理算法
- 将堆区划分成大小相等的区域进行管理
- Serial/Serial Old收集器
-
内存分配策咯
- 首先在新生代Eden区分配,如果内存不够触发一次Minor GC
- 否则分配到老年代
- 大对象直接到老年代
- 对象晋升老年区会判断内存大小,如果不够触发Full GC
Class对象
-
Class文件结构
- MagicNumber魔数,用来确定是不是.class文件
- Class文件的版本号,用来判断Jdk是否支持
- 常量池
- 字面量,文本字符串,被声明为final的常量
- 符号引用
- 类和接口的名称
- 字段名称和描述符
- 方法名称和描述符
- 访问标志
- 是否final
- 是否public,否则是private
- 是否是接口
- 是否可用invokespecial字节码指令
- 是否是abstact
- 是否是注解
- 是否是枚举
- 类索引、父类索引和接口索引集合
- 字段表集合(除了方法内声明的变量)
- 方法表集合
- 属性表集合
-
初始话的时机
- 非final的static变量
- final static String s = new String(“s”);
- 反射
- new一个对象
- 调用静态方法
-
类加载过程
- 加载
- 根据类命获取这个类的二进制字节流
- 将静态存储结构转化为方法区运行时数据结构
- 在堆中生成一个代表这个类的java.lang.Class对象,作为方法区数据访问入口
- 验证
- 文件格式验证
- 元数据验证
- 是否有父类
- 父类是否时final的
- 字段,方法是否和父类冲突
- 字节码验证
- 符合引用验证
- 准备
- 对static类变量分配内存并设置默认值
- 都在方法区中分配
- 如果是static final 设置为指定的值
- 解析 将符号引用替换为直接引用
- 类或接口解析
- 字段解析
- 方法解析
- 接口方法解析
- 初始化
- 父类static变量
- 父类static代码块
- 子类static变量
- 子类static代码块
- 父类普通代码块
- 父类构造器
- 子类普通代码块
- 子类构造器
- 加载
-
双亲委派模型
- Bootstrap 类加载器
- Extension 类加载器
- Application 类加载器
- 定义
除了顶级父类,都要把类加载的任务交给父类加载器处理,父类加载器处理不了,自己在处理