JVM探究
- 请你谈谈你对JVM的理解?java8虚拟机和之前的变化更新?
- 什么是OOM,什么是栈溢出StackOverFlowError?怎么分析?
- JVM的常用调优参数有哪些?
- 内存 快照如何抓取,怎么分析Dump文件?
- 谈谈JVM中,你对类加载器的认识?
-
JVM的位置
-
JVM的体系结构
-
类加载器
-
虚拟机自带的加载器
-
启动类加载器(根加载器)rt.jar包
-
扩展类加载器 /lib/ext,父类加载器为null。null的原因是java访问不到,因为java的基层是用C、C++写的。
-
应用程序加载器 ,父加载器为扩展类加载器
-
-
双亲委派机制
即用一个类时,会向上委托,一直到根加载器,若找到就用根加载器中的类,找不到就抛出异常,在子类即扩展类加载器中找,找到就用,找不到就再向下,层层递进,直到找到,若最后都没找到就抛出一个ClassNotFound。
-
沙箱安全机制
-
Native
-
凡是带了native关键字的,表名java作用范围达不到了,需要调用底层C语言库。会进入本地方法栈,调用本地方法接口(JNI)
-
JNI的作用是扩展java的使用,融合不同的语言为java使用。最初是融合C和C++。
-
java诞生的时候C和C++横行,想要立足,必须调用C和C++程序,因此,在内存中专门开辟了一块标记区域:Native Method Area,登记native方法,最终在执行的时候通过JNI加载本地方法库中的方法
-
-
PC寄存器
程序计数器:每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向一条指令的地址,也即将要执行的指令代码),再执行引擎读向下一条指令,是一个非常小的空间,几乎可以忽略不计。
-
方法区(Method Area)
方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法,如构造函数,接口代码也在此定义,简单说,所有定义方法的信息都保存在该区域,该区域属于共享区间。
静态方法、常量、类信息(构造函数,接口定义),运行时的常量池存在方法区中,但是实例变量存在堆内存中,和方法区无关。
static、final、Class、常量池
-
栈
栈:先进后出(桶)
队列:先进先出(FIFO)
栈内存,主要负责程序的运行,生命周期和线程同步,线程结束,栈也就释放内存,对于栈来说不存在垃圾回收。
栈:8大基本类型+对象引用+实例的方法
栈满了:StackOverflowError
-
三种JVM
-
sun公司的Hotspot
-
BEA: JRockit
-
IBM: J9 Vm
-
-
堆(Heap)
- 一个JVM只有一个堆内存,堆内存的大小是可以调节的。
类加载器读取了类文件后,一般会把什么东西放到堆中?类、方法、常量、变量~,保存引用类型的真是对象;
-
新生区(伊甸园区)Young/New
-
养老区 Old
-
永久区
-
说明:一般垃圾回收回收新生区的伊甸园区,而经历了垃圾回收没有被回收的就会进入幸存区(幸存0区和幸存1区也是不断交换的而不是固定的)。而在幸存区定了一个次数(例30次),若在经历30次的垃圾回收后,就会进入老年区。一般GC垃圾回收发生在伊甸园区和老年区。
-
堆内存满了:OOM
-
JDK8以后,永久区改名为元空间
-
-
新生区、老年区
新生区:
- 类:诞生和成长的地方,甚至死亡
- 伊甸园:所有的对象都是在伊甸园区new出来的
- 幸存者去(0,1)
过程:假设伊甸园区有10个空间,当伊甸园区满了之后,就会触发一次轻GC,将没有引用的对象回收,而还有引用的对象就会进入幸存者区,当幸存者区也满了之后,就会触发一次重GC,将伊甸园区和幸存者区都清一遍,幸存下来的进入老年区,当老年区经历多次重GC后也满了,就会出现OOM。
经研究:99%对象都是临时对象
-
永久区
这个区域常驻内存的,用来存放Java自带的Class对象,Interface元数据。存储的都是Java运行时的一些环境或类信息,一般不存在垃圾回收,在关闭JVM的时候就会释放这个区域的内存。
永久区什么时候会崩掉呢?
一个启动类,加载了大量的第三方jar包。Tomcat部署了太多的应用。大量动态生成的反射类。这些不断的被加载,指导内存满,就会出现OOM。
-
堆内存调优
-Xms:设置初始化内存大小,默认1/4
-Xmx:设置最大分配内存,默认1/64
-Xms1024m -Xmx1024m -XX:+PrintGCDetailse:打印GC垃圾回收信息
-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError:OOM的Dump
-
GC
GC垃圾回收并不是对这三个统一回收,GC垃圾回收发生在新生代与老年代,其中大部分在新生代。
- 新生代
- 幸存区(from,to)
- 老年区
GC两种回收:轻GC(普通的GC),重GC(全局的GC)
GC题目:
-
JVM的内存模型和分区,详细到每个区放什么?
-
堆里面的分区有哪些?Eden,from,to,老年区,说说他们的特点。
-
GC的算法有哪些?标记清除法,标记压缩,复制算法,引用计数器,怎么用的?
引用计数法:
计数器进行计数,对象C被引用0次,所以会被清除出去。
复制算法:
复制算法就是将幸存区中一个里面的数据复制到另一个里面,这时,空的那个就变成to区。这个算法是为了保证to区永远干净。
- 好处:没有内存碎片
- 缺点:浪费了内存空间。永远有一半空间是空的(to区)
复制算法的最佳使用场景:对象存活度较低的时候。
-
标记清除算法
对内存中的对象进行扫描,对存活的对象进行标记,然后将没有标记的对象进行清除。
优点:不需要额外的空间
缺点:两次扫描,浪费时间,且会产生内存碎片。
-
标记压缩(也称标记清除压缩)
在标记清除的基础上,再次扫描,向一端移动存活对象。但多了一个移动成本。
-
轻GC和重GC分别在什么时候发生?
总结:
内存效率:复制算法>标记清除算法>标记清除压缩算法(时间复杂度)
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
年轻代:
- 存活率低
- 复制算法
老年代:
- 标记清除
-
JMM(Java Memory Model:Java内存模型)
-
什么是JMM
-
它干嘛的?(官方、其他人的博客、对应的视频)
作用:缓存一致性协议,用于定义数据读写规则。(遵守,找到这个规则)
-
它该如何学习?
-