目录
[1 JVM的内存区域划分](#1 JVM的内存区域划分)
[2 JVM的类加载机制](#2 JVM的类加载机制)
[2.1 双亲委派模型](#2.1 双亲委派模型)
[3 垃圾回收机制](#3 垃圾回收机制)
本篇文章,主要是总结面试中所涉及到的Jvm的内容。
1 JVM的内存区域划分
Jvm实际上就是一个Java进程,每个Java进程就是一个Jvm实例。
一个进程运行过程中,就要从操作系统这里申请到一些内存资源。
JVM当然也是如此,搞一大块内存,供Java代码执行时使用。
JVM把这一块内存,又划分出几个区域来,作为不同的用途。

这里经常会出现这样的问题。

2 JVM的类加载机制
类加载机制就是把类从硬盘(文件)加载到内存中,Java程序,最开始写的是一个 .java 文件,然后编译成 .class 字节码文件,当运行Java程序时,JVM就会读取 .class 文件,把文件的内容放到内存中,并且构造成 .class类对象。
类加载是一个很复杂的流程,此处就简单介绍下这里的大致流程。
1 加载
找到.class 文件,打开文件,读取文件内容,并且尝试解析格式。
2 验证
检查一下当前.class文件的格式,是否符合要求。
3 准备
给类对象分配内存,最终的目标,是构造出完整的类对象。
分配出来的内存空间,内容就是全0的值。(此时此刻,类对象上的static成员也就都是0)
4 解析
主要是初始化类对象中涉及到的一些字符串常量。
其实字符串常量已经在.class 文件中有了,直接读到内存中就行了。
这里将字符串常量读到内存中的操作,就是将常量池内的符号引用替换为直接引用的过 程。怎么理解呢?
符号引用代表的意思,在.class文件中,不知道字符串真实的内存地址是在哪里的,只能知 道一个相对的偏移量,我知道字符串的内容在.class文件的哪个地方。
等到把字符串内容加载到内存之后,就可以把真实的地址,替换到刚才的符号引用这里了。
5 初始化
对类对象进行更具体的初始化操作,初始化静态成员,执行静态代码块,加载父类.....
2.1 双亲委派模型
那么类加载过程中,怎么找到.class文件呢?这就要提到双亲委派模型了。

而双亲委派模型,就描述了类加载的流程


每个类加载器,都是只有自己的"父亲",所以父亲委派模型,我觉得是更合理的。
类加载中,更重要,更关键的其实是针对.class 文件的解析校验。
那么一个类,在什么时机会被加载呢?
类的加载使用了懒汉模式。用到了才加载.
第一种是构造类的实例时,第二种是使用了类的静态方法/静态属性时,第三种是子类的加载会触发父类时。
3 垃圾回收机制
垃圾回收,到底是要做啥?对于Java来说,垃圾回收,回收的其实是"对象"而不是"字节"。换句话说GC并非是判定某几个字节是不是垃圾,而是去判定对象是不是垃圾,进一步的进行回收的。
但是JVM中有好几个内存区域,GC回收的是哪里的对象?
栈空间不需要GC回收.栈里面包含很多"栈帧",每个栈帧对应一个方法。该方法执行结束,此时这个栈帧就销毁了。栈帧上的局部变量啥的自然销毁。程序计数器同理,线程销毁,自然跟着销毁。
方法区,类对象,很少会涉及到对象的卸载。而堆,则是GC的主战场。
垃圾回收分两步:1.判断对象是否是"垃圾",2.释放对象的内存。
如果一个对象,在后续代码中,不会被继续使用到了就可以视为是垃圾了。
一个对象,如果没有任何引用指向它,也可以认为是垃圾了。
那么顺着这个思路,判断对象是否为垃圾的方式,可以有一个看这个对象是否有引用指向它。




而可达性的扫描是持续的,周期性的。
那么找到垃圾之后,如何清理垃圾,也就是如何清理对象呢?


复制算法的情况下,如果复制的内容少则无伤大雅,如果复制的内容多,则开销是很大的,并且内存利用率也不高,浪费了一半。

而设计JVM的大佬们,想到了个办法,集百家之长,结合上面集中方案,搞一个综合性质的方案在不同的场景下,使用不同的回收方式以达到扬长避短的效果。
这个就是分代回收。
