内存区域
线程私有
- 程序计数器 当前线程执行字节码的行号指示器
- 虚拟机栈 方法执行的内存模型 ,有局部变量表、操作数栈、动态链接、出口信息。
- 本地方法栈 执行native方法使用(原生方法、c或者c++实现)
线程共有
- 堆
- 元空间(使用直接内存) 直接内存 运行时常量池 字符串常量池 存放的是 字面量和符号引用。
- 直接内存
虚拟机对象
对象创建
- 类加载检查
- 分配内存 方式 ”指针碰撞“和”空闲列表” 内存分配保证线程安全 TLAB(为每个线程预分配) CAS+重试
- 初始化零值
- 设置对象头
- 执行init方法
对象访问定位
- 使用句柄 需要有句柄池
- 直接指针
其他部分
- 字符串常量池 ”“和intern()方法 “”+””也可以
- new String()
垃圾回收
GC root
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 本地方法栈(Native 方法)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 所有被同步锁持有的对象
引用类型
- 强引用(Strong Reference)
- 软引用(Soft Reference)内存不足时,会回收,用于内存敏感的高速缓存
- 弱引用(Weak Reference)只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,只要发现只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存
- 虚引用(PhantomReference) 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。主要用于跟踪对象被垃圾回收的活动。
不可达对象是否“非死不可”
- 对象经过可达性分析后,发现没有被GC ROOT关联,则会被第一次标记
- 判断对象是否覆盖了finalize方法,没有覆盖该方法,或者说finalize方法已经执行过了,则对象就只能等死。
无用的常量
- 字符串常量池中有字符串未被引用,可被回
无用的类
- 类的所有实例被回收
- ClassLoader被回收
- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
垃圾回收算法
- 标记-清除
- 复制
- 标记-整理
- 分代收集
垃圾收集器
- Serial(串行) 新生代采用标记-复制算法,老年代采用标记-整理算法。
- ParNew 收集器 多线程版本 CMS只能和它配合
- Parallel Scavenge JDK8默认使用 注重吞吐量 主要用于后台计算
- Serial Old
- Parallel Old
- CMS
CMS介绍
- 初始标记 STW 标记GC ROOT直连对象 非常快
- 并发标记 标记所有可达对象
- 重新标记 STW 时间比初始标记多一点
- 并发清除
缺点: CPU资源敏感、无法处理浮动垃圾、有大量碎片(标记-清除)
G1介绍 todo
类加载
类加载过程
- 加载 从zip包或者其他地方加载到内存,数组由jvm直接创建
- 验证 文件格式、元数据、字节码等验证
- 准备 对类变量分配内存,并附0值。final 为初始值
- 解析 将常量池中的符号引用替换为符号引用
- 初始化 主动使用才会 初始化类
- 使用
类加载器分类
- BootstrapClassLoader 顶层类加载器
- ExtensionClassLoader 扩展类加载器
- AppClassLoader(应用程序类加载器)
自定义类加载器,不想打破类加载器 重写 findClass。否则 重写 loadClass;