jvm内存划分哪几块?
- 堆
- 方法区
- 虚拟机栈
- 本地方法栈
- 程序计数器
哪些是线程共享、哪些是线程私有?
- 堆、方法区 为线程共享
- 虚拟机栈、本地方法栈、程序计数器 为线程私有
每一块内存存放的那些东西?
- 堆【对象实例、数组等动态分配的内存】
- 方法区【类信息、常量、静态变量、即时编译后的代码】
- 虚拟机栈【栈桢】
- 本地方法栈【本地方法的native栈桢】
- 程序计数器【当前线程执行的指令地址】
栈桢的具体介绍?
- 局部变量表【变量的存储】
- 操作数栈【从局部变量表获取变量计算后结果写回变量表】
- 动态链接【方法调用的符号引用到直接引用】
- 返回指令【处理return】
- 附加信息
堆内存的详细划分?
年轻代
- 2块 s区
- 1块 e区
- 默认比例 8e:1s:1s 老年代
- 默认比例 老年代:年轻代 = 2:1
方法区在jdk1.6、1.7、1.8中的变化?
| 版本 | 方法区位置 | 静态变量 | 字符串常量池 |
|---|---|---|---|
| 1.6 | jvm内存 | 方法区 | 方法区 |
| 1.7 | jvm内存 | 堆 | 堆 |
| 1.8 | 本地内存 | 堆 | 堆 |
垃圾判定算法?
引用计数器
- 每个对象添加个引用计数器,每当被引用时+1,引用失效的时候-1,为0时代表可以回收的垃圾对象;
- 简单高效,很难处理循环引用的问题。
可达性分析算法
- 从一系列GC Roots出发,找出可以到达的对象称之为 可达对象或者说存活对象,其余的为垃圾对象。
java语言中那些对象可以作为GC Roots
- 虚拟栈中局部变量表中的对象
- 本地方法栈中JNI中的对象
- 方法区中的静态变量
- 方法区中的常量
总结: 其实就是方法运行时要使用的对象比如虚拟机栈、本地方法栈;应用运行中共享的对象比如方法区中的常量、静态属性变量
垃圾回收算法
标记-清理
- 利用可达性分析算法,标记出 存活、垃圾对象
- 把垃圾对象占用的空间清空
- 产生很多碎片化内存
- 适合垃圾少、存活多的场景
标记-整理
- 利用可达性分析算法,标记出 存活、垃圾对象
- 存活对象移动整理
- 适合垃圾少、存活多的场景
复制
- 利用可达性分析算法,标记出 存活、垃圾对象
- 将存活对象顺序移动到另外一块干净的内存,清空之前那一半内存
- 适合垃圾多、存活少的场景
老年代为什么使用标记整理、年轻代使用复制算法?
- 老年代对象 存活多、垃圾少
- 新生代对象 存活少、垃圾多
常用的垃圾收集器?
新生代
- Serial 单线程
- ParNew 多线程
- Parallel Scavenge 多线程、可控吞吐量、自适应调整新生代和老年代的比例 以达到停顿和吞吐量的平衡策略
老年代
- SerialOld(带整理)单线程
- ParallelOld(带整理)多线程
- CMS(带整理UseCMSCompactAtFullCollection(默认开启)、CMSFullGCsBeforeCompaction) 【初始标记STW、并发标记、重新标记STW、并发清理】
G1
什么情况下会发生young GC、什么情况下会发生full GC
- Eden 区无法容纳新产生的对象时发生young GC
- 老年代中的空间不足以存放新产生的对象,大对象会更容易引发fullGC,没有足够的连续空间容纳一个大对象
内存模型中不会发生oom的是?为什么?
- 程序计数器
- 每个线程私有的程序计数器内存 因为其大小固定、存储简单,所以不会oom
其他几块内存发生oom的场景?
- 堆中 产生对象的所占用的堆内存大于GC后剩余的堆内存产生oom
- 方法区 类信息 等数据大于方法区的内存时,理论上1.8之后,除非超出的机器的剩余物理内存oom
- 虚拟机栈 方法调用层次太深大于虚拟机允许的深度 soe;递归调用,不停产生的栈桢占用空间大于虚拟机栈内存oom
- 本地方法栈 本地方法调用层次太深大于允许的深度 soe;递归调用,不停产生的栈桢占用空间大于本地方法栈内存oom
java对象的内存分布
- 对象头 8byte
- classpointer 4byte
- instancedata 具体数据类型
- padding 对齐填充 8byte的倍数
栈桢
- 局部变量表 变量存储
- 操作数栈 从局部变量表拿数据计算并写回局部变量表
- 动态连接 方法的调用链这种符号引用转道直接引用
- 返回指令
- 附加信息
如何排查oom?
获取堆转储 Heap Dump文件
- 方式1:jmap
- 方式2:jcmd
- 方式3: -XX:+HeapDumpOnOutOfMemoryError
分析 HeapDump 文件
- VisualVM
如何排查soe
- 发生soe时,分析java打印的异常堆栈信息
- 从异常堆栈信息中找到引发异常方法调用链路的末尾,通常是递归调用导致超出栈深度
- 解决:-Xss调整栈大小、使用迭代代替递归
如何排查cpu 飙高?
- jps 查看java进程pid
- top -Hp pid 查看进程中线程详细信息
- 找出较高栈用的线程tid
- 通过 【printf "%x\n" tid】 将16进制转10进制 tid16
- jstack | grep tid16