一、概述
Java语言中一个显著的特点就是引入了垃圾回收机制,使c/c++程序员最头疼的内存管理问题迎刃而解,它使得Java程序员在编写程序的时候不用考虑内存管理,JVM替我们完成了这部分工作。
二、回收步骤
JVM的垃圾回收工作主要完成3件事:
1、确定哪些内存需要回收?
2、确定什么时候需要执行垃圾回收?
3、如何执行垃圾回收?
- 1
- 2
- 3
三、何为垃圾?
不可达的对象会变成垃圾。什么叫做不可达?就是没有办法引用了,引用不了它,不能为我们所用。一个对象有以下情况会变成垃圾:
1.对非线程的对象来说,当所有的活动线程都不能访问该对象,则该对象变为垃圾。
2.对线程对象来说,满足上面的条件,且线程未启动或者已停止。
- 1
- 2
四、啥时回收?
时间不确定。
垃圾回收机制是由垃圾收集器(Garbage Collection,即GC)来实现的,GC是后台的守护进程。它的特别之处在于它是一个低优先级进程,但是可以根据内存的使用情况动态调整优先级。因此,GC会在内存中低到一定限度时才自动运行,从而实现对内存的回收。这就是垃圾回收的时间不确定的原因。
为何要这样设计?因为GC也是进程,也要消耗CPU等资源,如果执行过于频繁,会对java程序的执行产生较大的影响(java解释器本来就不快),因此JVM的设计者们选择了不定期的进行垃圾回收。
五、怎样回收?
说来话长。概括的说,就是:分代分配内存,分代回收垃圾。
这里说的内存,主要是指JVM中的堆区,因为对象保存在这里。
在垃圾回收器回收内存之前,需要一些清理工作。
因为垃圾回收器只能回收通过new关键字申请的内存(在堆区),但是堆上的内存并不完全是通过new申请分配的。还有一些本地方法(一般是调用的C方法)。这部分“特殊的内存”如果不手动释放,就会导致内存泄露,而垃圾回收器是无法回收这部分内存的。所以需要在finalize中用本地方法(native method),如free操作等,再使用gc方法。
1、分代分配
将堆区分为3个区域:
轻生代(Young Generation)、老年代(Old Generation)、永久代(Permanent Generation)
这三个代里面,永生代
则对应JVM中的方法区,存放的是类的结构信息,以及运行时常量池之类的东东;而新生代
和老年代
分别用于存放不同时期的对象或大小不一的对象。这里面有一系列算法。简而言之,就像人的生命周期一样,新创建的对象放在新生代(比较大也可以直接放到老年代),而新生代又分为伊甸区和两个存活区,对象会在这些区域之间搬来搬去。
经过几轮回收淘汰以后,移到老年代。
2.分代回收
新生代:采用停止-复制算法。停止(Stop-the-world)”的意义是在回收内存时,需要暂停其他所 有线程的执行。
老年代:采用标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。
永久代:不一定需要回收。
2022.08.19
复制算法
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半,未免太高了一点。
标记 - 整理算法
复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。
根据老年代的特点,有人提出了另外一种“标记-整理”(Mark-Compact)算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
=======================================
2022.09.18
Major GC 是清理永久代。Full GC 是清理整个堆空间—包括年轻代和永久代。
CMS,全称“ Concurrent-Mark-Sweep”,是一款并发的、使用标记-清除算法的垃圾回收器,如果老年代采用CMS垃圾回收器,则需要在应用服务Java虚拟机启动参数中配置关键字:-“XX:+UseConcMarkSweepGC”。
使用场景:GC过程短暂停,适合对时延要求较高的服务,用户线程不允许长时间停顿。
算法缺点: 存在严重的内存碎片化。 另外,算法实现比较复杂。已成过去式,不推荐使用。
【什么是Stop The World ? 什么是OopMap?什么是安全点?】
进行垃圾回收的过程中,会涉及对象的移动。为了保证对象引用更新的正确性,必须暂停所有的用户线程,像这样的停顿,虚拟机设计者形象描述为「Stop The World」。也简称为STW。
在HotSpot中,有个数据结构(映射表)称为「OopMap」。一旦类加载动作完成的时候,
HotSpot就会把对象内什么偏移量上是什么类型的数据计算出来,记录到OopMap。在即时编译过程中,也会在「特定的位置」生成 OopMap,记录下栈上和寄存器里哪些位置是引用。这些位置就叫作「安全点(safepoint)。」 用户程序执行时并非在代码指令流的任意位置都能够在
停顿下来开始垃圾收集,而是必须是执行到安全点才能够暂停。
HotSpot是一款Java虚拟机。