JVM详细介绍
JVM的位置
JVM是运行在操作系统之上,相当于一个软件
JVM是用C、C++语言编写的
JVM结构
JVM调优几乎都是调堆里面的东西;
lombok插件,实际上在执行引擎上动态加载了get,set;
类加载器
通过一个类的全限名来获取描述此类的二进制字节流,这个动作放在JVM外部去实现,以便让应用程序自己决定如何去获取所需要的类,实现这个动作的代码模块称为“类加载器”
当一个对象创建之后,它的引用放在栈里面,对象本身放在堆里面
类加载器的种类:
1、启动加载器:根加载器,主要是加载环境变量目录下的核心api,如rt.jar;
2、扩展类加载:负责加载lib,ext目录下的所有jar包;
3、应用程序加载器:加载项目工程的ClassPath目录下的类库,可以自定义类加载器;
面试题:Class.forName 和 ClassLoader 有什么区别?
简单总结:Class.forName() 方法实际上也是调用的 CLassLoader 来实现的。
Class.forName 加载类是将类进了初始化,而 ClassLoader 的 loadClass 并没有对类进行初始化,只是把类加载到了虚拟机中。
双亲委派机制
当一个类在加载的时候,都会先委派它的父类加载器去加载,这样一层层的向上委派,直到最顶层的启动加载器;如果顶层无法加载,即找不到对应的类,就会一层层的向下查找,直到找到为止。这就是双亲委派机制。
目的:保证安全,防止开发员自定义与源码中相同的类;
沙箱安全机制
Java安全模型的核心就是Java沙箱;
沙箱:是一个限制程序运行的环境;
沙箱机制就是将Java代码限定在JVM特定的运行范围内,并且严格限制代码对本地资源的访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏;
系统资源:CPU、内存、文件系统、网络;
Native
凡是带有native关键字的,说明Java的作用域达不到了,会去调用底层C语言的库;
native关键字修饰的方法会进入本地方法栈,然后调用本地方法,本地接口;
程序计数器
每个线程都有一个程序计数器,是线程私有的,相当于一个指针,指向方法区中方法的字节码,在执行引擎读取下一条指令。是一个非常小的内存空间。
方法区
所有线程共享,所有字段和方法字节码,以及一些特殊方法,
所有定义的方法的信息都保存在该区域,属于共享空间。
静态变量,常量,类信息,运行时的常量池,实例变量存在堆内存中,和方法无关
栈
main函数最先被压入栈中,最后弹出;
栈存放的内容:
八大基本类型;
对象引用;
实例方法;
程序正在执行的方法,一定在栈的顶部;
堆
Heap,一个JVM只有一个堆内存,堆内存大小是可以调节的。类加载器读取了类文件后,一般把类的实例放在堆中,即堆保存的是引用类型的真实对象;
堆分为三个区域:
1、新生区:伊甸园,幸存0区,幸存1区
2、养老区
3、永久存储区
垃圾回收种类:轻GC,重GC,垃圾回收一般在伊甸园区和养老区
堆内存满的话,会出现OOM错误 java.lang.OutOfMemoryError:Java heap space
出现的几种情况:
1、一个启动类加载了大量第三方jar包
2、Tomcat部署了太多应用
3、大量动态生成反射类
永久区:也叫元空间,存放jdk自带的Class对象,interface元数据,存放的是Java运行时的一些环境或者类信息,不能被回收;
面试题:在写程序的过程中,遇见过OOM吗?怎么解决的?
1、尝试扩大堆内存,看效果
2、使用专业工具分析内存,看一下那个地方出现了问题
GC
什么是垃圾回收:
释放垃圾占用的空间,防止内存泄漏;
做垃圾回收,必须知道哪些是垃圾:
1、引用计数法
通过在对象头中分配一个空间来保存该对象被引用的计数如果该对象被其他对象引用,则引用计数加一,如果删除对该对象的引用,则减一,当引用计数为0时,就会被回收;
缺点:出现相互引用的那种对象
2、可达性分析算法
通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,当一个对象到GC Roots没有任何引用链相连时,则证明该对象是不可用的;
GC Root 的对象:
1、栈中引用的对象;
2、方法区中类静态属性引用的对象;
3、方法区中常量引用的对象;
4、本地方法栈中引用的对象;
回收垃圾算法:
1、标记清除算法
2、复制算法
3、标记整理算法
4、分代收集算法分代收集算法