JVM王炸面试知识脑图 学弟看完进了阿里
导图地址:
https://mm.edrawsoft.cn/mobile-share/index.html?uuid=3f88d904374599-src&share_type=1
类加载器
双亲委派模型
当一个类收到类加载请求,它首先把类加载请求交给父类(如果还有父类,继续往上递交请求).如果父类无法加载该类,再交给子类加载
防止内存中出现多份同样的字节码对象 (出于安全性考虑)
保证核心.class不被篡改
如何打破双亲委派模型
1.自定义类加载器,重写loadClass方法
2.使用上下文类加载器
打破双亲委派模型的案例
Tomcat
JDBC
类加载器
应用程序类加载器 AppClassLoader
使用java语言编写
加载范围
负责加载环境变量classpath或系统属性java.class.path指定的类库
自己写的类都是由应用程序加载类加载的
扩展类加载器 ExtClassLoader
使用java语言编写
加载范围
从java.ext.dirs指定的路径下加载类库;或者从JDK安装目录的jre/lib/ext目录下加载类库
如果用户自定义的jar包放在jre/lib/ext下,也会自动由扩展类加载器加载
引导类加载器 BootStrapClassLoader
引导类加载器使用C/C++语言实现,在JVM内部
加载范围
用于加载核心库
只加载包名为java,javax,sun开头的类
JVM组成
存在线程安全问题
方法区(永久代)
方法区是所有线程共享的区域.用于存储被Java虚拟机加载的类信息,常量,静态变量,即时编译后的数据
即时编译: 为了平衡启动和执行的效率,JVM结合解释执行和编译执行的特点,进行解释执行并对热点代码进行编译优化,这样的执行过程叫即时编译
当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常
1.8之后叫元空间,使用物理内存,不受jvm参数限制
堆
堆是虚拟机管理中内存最大的一块,被所有线程共享.所有对象实例以及数组都要在堆上分配内存
堆是垃圾管理器管理的的主要区域,因此也被称为"GC堆"
GC : 这里指Java的垃圾回收机制
常量池1.8在堆中
分为新生代,老年代 内存大小比例为 1: 2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"><html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'微软雅黑'; font-size:12pt;">新生代又分为Eden和Survivor (From与To,这里简称一个区)两个区。加上老年代就这三个区。数据会首先分配到Eden区当中(当然也有特殊情况,如果是大对象那么会直接放入到老年代(大对象是指需要大量连续内存空间的java对象)。当Eden没有足够空间的时候就会触发jvm发起一次Minor GC,。如果对象经过一次Minor-GC还存活,并且又能被Survivor空间接受,那么将被移动到Survivor空间当中。并将其年龄设为1,对象在Survivor每熬过一次Minor GC,年龄就加1,当年龄达到一定的程度(默认为15)时,就会被晋升到老年代中了,当然晋升老年代的年龄是可以设置的。</span></p></body></html>
新生代
- 一个 Eden 区
- 两个 survival 区 ( From Survivor、To Survivor ),无论什么时候总有一块 survival 是空闲的
- 为什么需要两个 survival 区设置两个Survivor区最大的好处就是解决了碎片化
老年代( 垃圾回收后在 survival区存活 15 (默认) 次后进入 ) , 在老年代一般使用 标记-清除算法 或者 标记整理算法
为什么要这么分代 : 可以根据各个代的特点进行对象分区存储,更便于回收,采用最适当的收集算法
新生代中,每次垃圾收集时都发现大批对象死去,只有少量对象存活,便采用了复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须采用“标记-清理”或者“标记-整理”算法。
线程私有
本地方法区
本地方法栈中就是C和C++的代码编译的方法
程序计数器
保存当前线程所正在执行的字节码指令的地址(行号)
栈
栈是线程私有的,每个方法在执行的时候都会创建一个栈帧,方法先进后出
栈帧
- 操作数栈操作数栈可理解为java虚拟机栈中的一个用于计算的临时数据存储区。
- 局部变量表存放局部临时数据
- 动态链接在程序运行期间将符号引用转为直接引用
- 出口方法执行完毕返回的位置