JVM学习笔记
复习之前学的内容,同时补充以下知识点:JVM的双亲委派机制、伊甸区与老年代相关知识;
双亲委派机制
双亲的含义应该就是AppClassLoader有:ExtClassLoader和BootstrapClassLoader“两个”父加载器。
首先介绍Java中的类加载器
Java中的类加载器
Bootstrap ClassLoader(启动类加载器),默认加载jdk\lib目录下jar中的诸多类。可以使用-Xbootclasspath指定。
Extension ClassLoader(扩展类加载器),默认加载jdk\lib\ext目录下的jar中的诸多类。可以使用java.ext.dirs系统变量更改。
Application ClassLoader(应用程序加载器),应用程序加载器,负责加载开发人员所编写的诸多类。
User ClassLoader(自定义加载器),自定义类加载器,当存在上述加载器解决不了的特殊情况时,或者存在特殊要求时,可以自行实现类加载逻辑。
关系图:
双亲委派
通俗故事:
- 假设用户刚刚摸鱼时写了个Test类想进行加载,此时会发送给应用程序类加载器AppClassLoader;
- 然后AppClassLoader并不会直接去加载Test类,而是会委派于父类ExtClassLoader,来完成此操作;
- ExtClassLoader同样不会直接加载Test类,而是会继续委派父类BootstrapClassLoader;
- BootstrapClassLoader已经是顶层了,没有更高的父类加载器了,因此BootstrapClassLoader就从jdk\lib中搜索是否存在,因为这里是用户自己写的Test类,因此不会存在于jdk下,所以此时会给子类一个反馈;
- ExtClassLoader收到父类传回的反馈,知道父类加载器没有找到对应的类,爸爸靠不住,就只能自己来加载了,结果显而易见,自己也不行,只能给下面的子类加载器,AppClassLoader;
- AppClassLoader收到父类加载器的反馈,顿时明白,原来爸爸虽然是爸爸,但是终究不能管儿子的私事,所以此时,AppClassLoader就自己尝试去加载。
- 结果,就这样成功了,走了一大圈,兜兜转转还是自己干。
什么是双亲委派
为什么使用双亲委派
专业性解释:①避免类的重复加载;②防止核心API被篡改;
为了避免原始类被覆盖的问题。
老子走过的路,小子不用走
比如,用户编写了一个Object类,放入程序中加载。
当没有双亲委派机制时,就会出现重复的Object类,给开发人员造成很大的困扰,本来就只需要基于JDK开发就好了,现在还得把JDK中的类全记住,避免编写重复的类。
当存在双亲委派机制时,整个事情就不一样了,每次加载类时,都会遵循双亲委派机制,去问父类是否可以加载,如果可以呢,那就不需要再次加载了,这样事情就简单了。
Tomcat为什么要自定义类加载器
如何打破双亲委派模型(太高级,尝试看一下)
为什么要考虑这个问题?
- 自定义类加载器时,重写loadClass方法。
双亲委派还有什么
运行时数据区
蓝色部分是多个线程共享部分;
绿色部分为单个线程独享部分;
方法区
;
解释器
JIT编译器
GC
堆区
程序计数器
记录下一条待执行指令的地址;
- 是物理寄存器的抽象实现;
- 用来记录下一条待执行指令的地址;
- 它是程序控制流的指示器,循环、if else、异常处理、线程恢复等都依赖它来完成;
- 解释器工作时就是通过它来获取下一条需要执行的字节码指令的;
- 是唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域。
Java方法栈
虚拟机栈是线程私有的,每个线程创建时都会创建一个虚拟机栈,栈内保存一个栈帧,一个栈帧就对应一个方法。
- 虚拟机栈是线程私有的
- 一个方法开始执行,栈帧入栈、方法执行完对应的栈帧就出栈,所以虚拟机栈不需要进行垃圾回收
- 虚拟机栈存在OutOfMemoryError,和StackOverFlowError;
- 线程太多,就会出现OutOfMemoryError,线程创建时没有足够的内存去创建虚拟机栈了;
- 方法调用层数过多,就会出现StackOverFlowError;
- 可以通过-Xss来设置虚拟机栈的大小。
栈帧:
操作数栈:也可以叫做操作栈,是栈帧的一部分,操作数栈是用来执行字节码指令过程中用来进行计算的。
本地方法栈
C/C++语言写的一些代码