1.jvm内存模型分为几部分?
程序计数器 虚拟机栈 本地方法栈 堆 元数据区 直接内存
2.那些是线程私有的?那些是共有的
程序计数器 虚拟机栈 本地方法栈是私有的 堆 元数据区 直接内存 是共有的
程序计数器,唯一不会产生oom的 主要是大方向控制线程的程序运行到第几行 在第几行应该唤醒
字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。
另外,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存
虚拟机栈 私有的是一个stack 每个虚拟机栈进入一个方法就会产生一个栈帧
3.栈帧由什么组成?
栈帧包括 局部变量表、操作数栈、动态链接、方法出口信息
局部变量表 又包括了 常用数据类型 和 对象的引用
4.虚拟机栈会产生什么异常?由什么原因引起的?
StackOverFlowError 和 OutOfMemoryError
sofe 就是递归太多的时候不能继续申请了
oom是 栈帧可以继续申请,但是虚拟机内存已经没有足够空间让它申请内存了
5.虚拟机栈的大小如何设置?
-Xss 一般设置为256k
6.如何跳出一个栈?
出栈的方式有两种 return 或者 throw异常
本地方法栈 本地方法 那些点不下去的方法 比如cas的一些方法 其他和虚拟机栈一样
堆
7.参数大小是
-Xmx 堆的最大内存大小 -Xms堆的初始内存大小
8. 为什么要设置成一样大?
以避免每次垃圾回收完成后JVM重新分配内存,减少扩容的时候时间;
9.年轻代相关问题?
年轻代 eden survivor old三个区 -Xmn Sun官方建议年轻代的大小为整个堆的3/8左右 如果Xmx设置为8g 那么Xmn设置为3g
survivor区分为from和to区
eden和survivor 的比例是8:1:1
Sun官方建议年轻代的大小为整个堆的3/8左右
-XX:SurvivorRatio=4 设置eden和survivor的比例大小4:1
10.对象创建后是如何在堆中存储的?
创建对象或者数组 对象会先在堆中的年轻代生成 随着gc的过程,对象存活后,会在survivor的from区和to区反复复制,当次数打到设置的阈值后(XX:MaxTenuringThreshold),就会放到老年代
11.出现oom的原因可能有哪些?
java.lang.OutOfMemoryError: GC Overhead Limit Exceeded 虚拟机花费大量时间回收垃圾,但是实际清理出的内存空间很少
java.lang.OutOfMemoryError: Java heap space 内存空间不足以创建足够的对象
12.什么是youngCG?
发生在新生代的gc 会去清理 eden区 和from区,youngGC会检查堆中最大的连续空间是否大于新生代中存储的所有对象的大小,如果大于那么可以触发youngGC;此外还有空间担保机制(后面会有)
13.什么时候会出发youngGC?
创建大量对象,新生代没有足够的内存
14.youngGC采用什么算法?
复制算法
15.什么是fullGC
老年代或者元数据区(方法区)内存不足
16. 什么情况发生fullGC
1.新生代的to区 向 老年代晋升对象时,老年代没有足够的内存,老年代的连续空间,放不下新生代过来的的对象
2.如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize(元数据空间的初始大小),也会触发FullGC,或者之前1.7的时候方法区放不下了 也会触发fullGC,同时带着老年代也来一次fullGC
3.空间担保机制失败,每次youngGC时,会检查老年代是否有足够的连续的空间存放 所有的新生代的对象,如果大于那么进行youngGC,
如果老年代最大连续空间大小 小于 新生代的大小并且开启了空间担保机制HandlePromotionFailure 那么就会检查历次最终晋升到老年代的平均内存大小(这里注意是平均,刚才是所有)是否小于老年代最大连续空间的大小
如果老年代最大连续空间大小 大于 每次晋升的平均值 证明有大概率的可能能放得下这次晋升的对象产生的内存大小;然后开始youngGC;
如果老年代最大连续空间大小 小于 每次晋升的平均值那就是没空间了,和case1是一种情况,老年代没空间放了;那么进行一个FullGC
如果HandlePromotionFailure没有开启担保机制,那就直接fullGC,和case1是一样的
17.字符串常量池存放在jvm中那个区?
7版本后就移动到了堆中
String a = new String("hello") 在堆中 创建了两个对象
元数据区
它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
18.元数据区的常量池存放的是什么?
1.class常量池,相当于class文件的仓库,是class的一部分,是class文件中的一部分 每个编译好的class文件都会有一个class常量池 可以理解为class文件的资源仓库 主要存放 字面量(文本字符串、声明为final的常量值等)和符号引用(有三类:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符)
2.运行时常量池 这个在元数据区 动态的 class文件中的常量池在类加载后进入方法区的运行时常量池存放 这里的方法区就是元数据区 可以动态添加的常量池 比如string的intern方法 可以吧string放到这个常量池里面
19.元数据区相关参数,及产生的异常?
1.-XX:MaxMetaspaceSize 标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制
-XX:MetaspaceSize 调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。
2.oom:metaSpace
## 20. 为什么要设置元数据区?
1.空间无限大,上限是本地内存的大小
2.之前永久代发生fullGC那么也会连带着堆中发生gc,占用时间
jvm 性能调优
21.手动配置过参数吗?
4g内存的的服务器 用了8g的内存配置上线 本身系统占用了1.5个g,堆的大小配了2g,xss设置成了1mb,这个时候刷数据,请求一多,直接导致了oom 后来查询发现是xss设置过大,改为256k后正常
导入excel文件 poi会一次性加载所有的行,导致oom 解决方案:修改堆的大小xmx,xss调整到适当大小;业务方对数据先进性处理不要一次导入太多条数;
22.用过什么命令,看过堆的内存参数等等?
jps -l 查看所有运行的java 程序
jstat
jstat -gc pid 垃圾回收统计
jstat -gcutil pid 总结垃圾回收统计
jstat -gcnew pid 新生代垃圾回收统计
jmap
jmap -histo pid可以打印出当前堆中所有每个类的实例数量和内存占用
jconsole
直接输入就可以看到相关内容
这里我点了一下执行gc 还是挺快的
如果想查看自己jvm的配置 如果使用idea的话可以从content->bin->vmoptions这个文件夹里面看到
发现 这里用的还是g1