随手笔记,仅供参考,欢迎纠正,不定时更新。
区域划分
1.程序计数器
当前线程所执行的字节码的行号指示器
唯一无oom 区域。线程私有
2.java虚拟机栈
栈帧(stack frame): 局部变量,操作数栈,动态连接,方法出口 (对应执行方法) 栈帧随着方法调用而创建,随着方法结束而销毁
局部变量(基本类型,reference类型,returnAddredss) 局部变量槽(slot) long/double = 2 slot
编译期完成局部变量表分配,方法运行期间不改变slot数量
栈溢出异常: 线程栈深度 > jvm允许深度
oom: 栈可动态扩展,无法申请到足够的内存 (hotspot 栈容量不可动态扩展,所以oom只可能发生在申请阶段)
3.本地方法栈
同虚拟机栈相似,为本地方法服务。 java虚拟机规范对本地方法语言没有任何强制规定。
hotspot 直接把本地方法栈和虚拟机栈合一
4.堆
几乎所有的对象实例和数组
(本地分配缓存区)TLAB: 线程私有分配空间,解决指针碰撞,提示分配效率
oom: 堆没有内存完成对象分配,并且无法扩展
5.方法区
类型信息,常量,静态变量,编译后的代码缓存
类型信息至于 元空间存储(meta-space) ,元空间并不在虚拟机中,而是使用 本地内存。
常量,静态变量 移至堆中处理
oom: 例如 string intern()方法
6.直接内存
nio 通道(channel) 的 缓冲区(buffer)使用native库直接分配堆外内存。使用java 堆中DirectByteBuffer 进行引用操作。
对象创建
内存分配方法:基于java堆是否规整判定(java堆规整由垃圾回收器的空间压缩整理能力决定)
指针碰撞(bump the pointer: 规整 cas方式解决并发的碰撞处理
空闲列表 (free list): 不规整 CMS 使用清除算法(sweep) 理论上只能使用空闲列表方法,实际CMS设计了分配缓冲区 ,又btp方式 进行分配。
java对象组成
1,对象头
1,Mark Word
2,指向类的指针
3,数组长度(只有数组对象才有)
2,实例数据
3,对齐填充字节 (自动内存管理系统要求对象大小是8字节的倍数)
锁状态 | 25bit | 4bit | 1bit | 2bit | |
23bit | 2bit | 是否偏向锁 | 锁标志位 | ||
无锁 | 对象的HashCode | 分代年龄 | 0 | 01 | |
偏向锁 | 线程ID | Epoch | 分代年龄 | 1 | 01 |
轻量级锁 | 指向栈中锁记录的指针 | 00 | |||
重量级锁 | 指向重量级锁的指针 | 10 | |||
GC标记 | 空 | 11 |
1. 在32位系统下,存放Class指针的空间大小是4字节,MarkWord是4字节,对象头为8字节。
2. 在64位系统下,存放Class指针的空间大小是8字节,MarkWord是8字节,对象头为16字节。
3. 64位开启指针压缩的情况下,存放Class指针的空间大小是4字节,MarkWord是8字节,对象头为12字节。 数组长度4字节+数组对象头8字节(对象引用4字节(未开启指针压缩的64位为8字节)+数组markword为4字节(64位未开启指针压缩的为8字节))+对齐4=16字节。
内存泄漏:对象没有被回收;
内存溢出:内存分配新对象不足
可达性分析: gc roots包含
1.虚拟机栈,栈帧中本地变量表(局部变量,临时变量)
2.方法去 静态变量 和常量
3 jni 引用对象
4. jvm内部使用对象,如 基本类型class对象,nullpointException ,outOfMemoryError,系统加载类等
5.被同步锁(sync)持有的对象
6 jmxbean ,jvmti中的注册回调,本地代码缓存等。
方法区gc:
常量回收
不再使用的类型
垃圾收集器
serial 复制算法 单cpu 单线程 是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器
Serial 是一个单线程的收集器,它不但只会使用一个 CPU 或一条线程去完成垃圾收集工作,并且在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束。
ParNew Serial 收集器的多线程版本 java虚拟机运行在 Server 模式下新生代的默认垃圾收集器
默认开启和 CPU 数目相同的线程数
Parallel Scavenge 收集器也是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃圾收集器,
它重点关注的是程序达到一个可控制的吞吐量(Thoughput,CPU 用于运行用户代码的时间/CPU 总消耗时间,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务。自适应调节策略也是 ParallelScavenge 收集器与 ParNew 收集器的一个重要区别。
Serial Old 标记-整理算法 单线程 Serial 垃圾收集器老年代版本 Client 默认的 java 虚拟机默认的年老代垃圾收集器。
Parallel Old 标记-整理算法 多线程 Parallel Scavenge的老年代版本
CMS 标记清除算法 多线程 最主要目标是获取最短垃圾回收停顿时间
1.初始标记 标记 gc rooots 可以直接关联的对象,速度很快,需要暂停所有工作线程
2.并发标记 进行gc roots 跟踪的过程,和用户线程一起工作, 不需要暂停工作线程
3.重新标记 修正并发标记期间因用户程序继续运行导致的标记变动 需要暂停所有工作线程
4.清楚不可达对象 不需要暂停工作线程
由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行
cms无法处理浮动垃圾(floating garbage) ,有可能出现concurrent mode failure 失败,导致full gc(可以使用 seriavl old 作为预备方案)
浮动垃圾: cms并发标记和清理阶段产生的垃圾,在标记过程结束之后,无法处理,只有下一次处理
concurrent mode failure: cms收集时需要预分配空间处理分配新的对象,JDK6 从 68% -> 92% 老年代占比。预留空间不足以分配新对象出现并发失败。临时使用seriavl old 重新进行老年代垃圾收集(停顿时间长)
full gc时进行内存碎片整理
G1 Garbage first
对象CMS改进。
1. 基于标记-整理算法,不产生内存碎片。
2. 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收
但是需要消耗更大的算力和内存资源
G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。
初始标记
并发标记
最终标记
筛选回收
未完待续。。。。