1.描述一下jvm内存模型,以及这些空间的存放的内容 ?
- 堆内存划分的空间,如何回收这些内存对象,有哪些回收算法?
垃圾回收算法:标记清除、复制(多为新生代垃圾回收使用)、标记整理
- 如何解决线上gc频繁的问题?
- 查看监控,以了解出现问题的时间点以及当前FGC的频率(可对比正常情况看频率是否正常)
- 了解该时间点之前有没有程序上线、基础组件升级等情况。
- 了解JVM的参数设置,包括:堆空间各个区域的大小设置,新生代和老年代分别采用了哪些垃
圾收集器,然后分析JVM参数设置是否合理。 - 再对步骤1中列出的可能原因做排除法,其中元空间被打满、内存泄漏、代码显式调用gc方法
比较容易排查。 - 针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo 命令并结合dump堆内存文
件作进一步分析,需要先定位到可疑对象。 - 通过可疑对象定位到具体代码再次分析,这时候要结合GC原理和JVM参数设置,弄清楚可疑
对象是否满足了进入到老年代的条件才能下结论。
- 描述一下class初始化过程?
一个类初始化就是执行clinit()方法,过程如下
父类初始化
static变量初始化/static块(按照文本顺序执行)
Java Language Specification中,类初始化详细过程如下(最重要的是类初始化是线程安全的):
- 每个类都有一个初始化锁LC,进程获取LC(如果没有获取到,就一直等待)
- 如果C正在被其他线程初始化,释放LC并等待C初始化完成
- 如果C正在被本线程初始化,即递归初始化,释放LC
- 如果C已经被初始化了,释放LC
- 如果C处于erroneous状态,释放LC并抛出异常NoClassDefFoundError
- 否则,将C标记为正在被本线程初始化,释放LC;然后, 初始化那些final且为基础类型的类
成员变量 - 初始化C的父类SC和各个接口SI_n(按照implements子句中的顺序来) ;如果SC或SIn初始
化过程中抛出异常,则获取LC,将C标记为erroneous,并通知所有线程,然后释放LC,然后
再抛出同样的异常。 - 从classloader处获取assertion是否被打开
- 接下来, 按照文本顺序执行类变量初始化和静态代码块,或接口的字段初始化,把它们当作
是一个个单独的代码块。 - 如果执行正常,获取LC,标记C为已初始化,并通知所有线程,然后释放LC
- 否则,如果抛出了异常E。若E不是Error,则以E为参数创建新的异常
ExceptionInInitializerError作为E。如果因为OutOfMemoryError导致无法创建
ExceptionInInitializerError,则将OutOfMemoryError作为E。 - 获取LC,将C标记为erroneous,通知所有等待的线程,释放LC,并抛出异常E。
- 简述一下内存溢出的原因,如何排查线上问题?
内存溢出的原因
java.lang.OutOfMemoryError: ……java heap space….. 堆栈溢出,代码问题的可能性极大
java.lang.OutOfMemoryError: GC over head limit exceeded 系统处于高频的GC状态,而且
回收的效果依然不佳的情况,就会开始报这个错误,这种情况一般是产生了很多不可以被释放
的对象,有可能是引用使用不当导致,或申请大对象导致,但是java heap space的内存溢出
有可能提前不会报这个错误,也就是可能内存就直接不够导致,而不是高频GC.
java.lang.OutOfMemoryError: PermGen space jdk1.7之前才会出现的问题 ,原因是系统的
代码非常多或引用的第三方包非常多、或代码中使用了大量的常量、或通过intern注入常量、
或者通过动态代码加载等方法,导致常量池的膨胀
java.lang.OutOfMemoryError: Direct buffer memory 直接内存不足,因为jvm垃圾回收不
会回收掉直接内存这部分的内存,所以可能原因是直接或间接使用了ByteBuffer中的
allocateDirect方法的时候,而没有做clear
java.lang.StackOverflowError - Xss设置的太小了
java.lang.OutOfMemoryError: unable to create new native thread 堆外内存不足,无法为
线程分配内存区域
java.lang.OutOfMemoryError: request {} byte for {}out of swap 地址空间不够
- jvm有哪些垃圾回收器,实际中如何选择?