释放那些不再持有引用的对象的内存。
在java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随着线程而生,随着线程而灭。栈中的栈帧随着方法的进入和退出而执行者出栈和入栈的操作。每一个栈帧需要分配多大的内存基本上在类结构确定的时候就是已知的。当方法结束或者线程结束时,内存自然就跟随着回收了。因此在这几个区域的内存分配以及回收都具备确定性,不需要过多考虑回收的问题。
而java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有在程序处于运行期间时才知道会创建哪些对象,这部分的内存分配以及回收都是动态的,因此垃圾回收的对象主要是对堆和方法区的垃圾回收。
二、怎么判断一个对象是否需要回收?
1、引用计数法(最简单古老的方法):指将对象(也可以是内存或磁盘空间)被引用计数保存起来,当被引用的计数变为0时,表示该独享不再持有引用,垃圾回收器就将该对象的内存释放。但是这种方式不能解决两个对象互相循环引用的情况。
2、引用链法(现大多数jvm使用的方法):通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,但一个对象到“GC Roots”没有任何引用链相连时,则证明此对象不可用。
在java语言中,可作为GC Roots的对象包括下面几种:
虚拟机栈(栈帧中的局部变量表)中引用的对象
方法区中的类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中引用的对象
2.1、java中的四种引用以及用到的场景
软引用:软引用是用来描述一些还有用但并非必需的对象。在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。
弱引用:弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些。当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象
虚引用:虚引用是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例,那么它相当于没有引用。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知,在任何时候都可能被垃圾回收器回收。
使用场景:
1、利用软引用和弱引用解决OOM问题:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,当内存不足时,jvm会自动回收这些缓存图片对象所占用的空间,从而有效避免OOM的问题。
2、通过软引用对象重获方法实现java对象的高速缓存:比如我们创建一个user类,如果每次需要查询一个用户的信息,哪怕是几秒钟之前刚刚查过,都需要重新构建一个实例,这是需要消耗很多时间的。我们可以通过软引用和HashMap结合,先是保存引用方面:以软引用的方式对一个user对象的实例进行引用并保存到HashMap上,key为user的id,value为这个对象的软引用;另一方面是取出引用,缓存中是否有该user实例的软引用,如果有,从软引用中取得。如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,并保存对这个新建实例的软引用。
三、几种垃圾收集算法:
1、引用计数法:当对象的被引用计数为零时,释放该对象的内存
2、标记-清除法:通过引用链法标记可用对象,在标记完成后统一回收未被标记的对象。这种方法会产生大量不连续的内存碎片。
3、标记-压缩法:与标记-清除法一样标记可用对象,然后将所有标记的对象压缩到内存的一端,再将边界外的内存空间全部清理掉。这样不会产生内存碎片,提高了内存利用率。
4、复制算法:将原有的内存空间分成两块,每次只用其中的一块。垃圾回收时,将可用的对象复制到另一块内存中,然后清除掉正在使用的内存块中所有的对象。这种方法适合短生存期的对象,比如新生代里面的对象。