综述:类加载的过程 从.java文件,通过类的加载器(在这里为字节码文件,为可移植性提供基础),加载进JVM中,加载进JVM的方法区中。 当new 一个对象时,识别new这个操作,会检查对应的类是否加载,对应的方法区的为类的模板,通过模板来生成类的实例,类的实例保存在虚拟机栈(JAVA栈)中
一、JVM外,类加载器
1、类加载器的种类
- bootstrapClassLoader
- ExtensionClassLoader
- ApplicationClassLoader
- CustromClassLoader
2、双亲委派机制
- 原理:
- 解决的问题:保护沙箱环境的安全
- 总结:我爸是李刚,有事找我爸
二、JVM内
1、线程私有
- JAVA栈或虚拟机栈
- 本地方法栈
- PC
2、线程共享
- 堆
- 方法区
三、垃圾回收机制(主要是对堆内的垃圾回收)
1、关于方法区在JDK7和JDK8中的不同表现
-JDK7方法区为永久代 堆和方法区在一块 -JDK8方法区为元空间 在内存中,分开
- 优化:在一起其中一个回收,则另一个进行回收
2、关于堆内存的分配
- 1/3是年轻代,剩余为老年代
- 其中新生代又分为Eden区、from区和to区(两个可以互换,谁为空时谁为to)
- 内存大小可以调节 -xms -xmx调节堆内存的大小
3、垃圾回收算法
- 复制算法 (对应年轻代的回收)
- 标记清除 (对应老年代的回收)
- 标记整理 (对应老年代的回收)
4、垃圾回收器(基本忘记)
1、CMS(Concurrent Mark Sweep 并发标记清除 )(垃圾回收器实现了垃圾回收算法) 标记清除
主要流程如下:
- 初始标记 STW(Stop the world) GC过程中应用的程序会发生停顿 将老年代的死的标出来,还有就是跨代引用的(注意:因为使用的可达性分析法,但这次指指向root) STW
- 并发标记 将GCROOT下面的进行追溯 (线程还在运行,此时会产生新的对象) -并发标记预处理:希望减少下一个阶段重新标记的时间 将上一阶段并发脏的进行标为脏页 新生代可能又有老年代引用指向的对象(应minorGC来进行优化)
- 重新标记 STW 扫描卡表,找出死的
- 并发消除
优点和缺点
- 优点:部分实现多线程
- 缺点: 内存碎片太多,因为没有整理的算法,但是整理的算法会发生STW(纠结~)
G1
- 引出了分区的概念,对分代的概念进行了弱化
- 新生代和老年代的堆空间不再是确定的1:2,而是根据最大的停顿时间进行调整
- G1解决跨代引用不是卡表,为RSET,其中的RSET在每个region都存在,记录着当前的region和其他region之间的引用对象的关系
- G1的过程:分别为minor GC和mixed GC
minorGC的主要流程
- 标记阶段:从GCROOT开始,标记活跃对象
- 转移: 转移到新的region
- 重定位:换个区域重新指向
mixedGC的主要流程
- 标记阶段: 初始标记 并发标记 再标记
- 清理 (无法解决转移过程中准确定位地址的问题)
- 复制 涉及到GCROOT的一般会很慢
5、如何判断一个对象为垃圾
当没有印象指向他时,则为垃圾
判断方法
1、引用计数法
2、可达性分析法
啥样的引用可作为GCROOTs?
1、虚拟机栈中引用的对象
2、被static关键字修饰的 (static修饰的对象在JVM的整个生命周期中都存在)
3、synchronized同步锁所持有的对象
四、垃圾回收的过程
- 所有的类都是在Eden区进行new创建的,当Eden用完后,使用minor GC(Young GC)进行回收。回收完剩余的复制进幸存者0区,当幸存者这0区满时候,进行赋值幸存者1区。再来时,进行GC回收,from和to区将会进行交换,谁空谁是to区
- 当一个对象经历过15次minorGC还没被回收,年龄加1,扔进老年区老年区满时,则会执行FullGC,FULLGC则是将新生代和老年代一起进行回收
- 若FULLGC后仍没有空间,则报OOM错
- OOM的原因:Java虚拟机内存不够(内存指的都是堆内存),可通过调节-XMx(堆内存所占主机内存的比例)进行调整,或者是创建了一个大的对象不会进行回收(G1垃圾回收器)
五、引用的类型
- 强引用
- 弱引用 (在将要OOM时候进行回收)
- 软引用 (在任何情况下都进行回收)
- 虚引用 (擦屁股)
六、重要的一个问题
- 跨代的问题,存在跨代引用,新生代的对象被老年代所引用,则不会被回收
- 当新生代的对象要被回收时,需要遍历老年代,使用可达性分析法,去判断在老年代的引用是否还指向当前的对象,为了防止遍历老年代,引出记忆集
- 记忆集将老年代划分为若干小块,标识出记忆集中哪一块存在跨代引用
- 记忆集的实现方式为卡表(card table),记录非收集区域指向收集区域指针的集合
- 原理:堆内存的每一块区域形成卡页,卡表是卡页的集合。当存在跨代引用的时候,将卡页标记为脏页,每次minorGC只需要从卡表中找到卡页,避免遍历访问老年代