GC基本原理

GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停
(1)对新生代的对象的收集称为minor GC;
(2)对旧生代的对象的收集称为Full GC;
(3)程序中主动调用System.gc()强制执行的GC为Full GC。
不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型:
(1)强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)
(2)软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)
(3)弱引用:在GC时一定会被GC回收
(4)虚引用:由于虚引用只是用来得知对象是否被GC
\"在这里插入图片描述\"

强引用

强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器宁愿抛出OOM(OutOfMemoryError)也不会回收它。

说明

不要被这个强字吓到,以为这个引用就很厉害,其实强引用就是程序中使用的一般引用类型。举个简单的例子:

String s = new String(\"Hello world!\");

强可达
如果一个对象与GC Roots之间存在强引用,则称这个对象为强可达(strong reachable)对象。

当你声明一个变量并指向一个实例的时候,其实就是在创造一个强引用。
那么,既然叫强引用,它“强”在哪里呢?

这主要体现在JVM进行GC的时候,只要对象有强引用与其关联,就绝对不会对它进行回收,即使已经内存不足了也不会收回有强引用指向的对象。

如果你不需要使用某个对象了,可以将相应的引用设置为null,消除强引用来帮助垃圾回收器进行回收。因为过多的强引用也是导致OOM的罪魁祸首。

s = null;

显式地设置消除引用,或已超出对象的生命周期范围,则JVM会认为该对象不存在引用,这时就可能会回收这个对象。但是具体什么时候收集这要取决于具体的GC算法。

如果在一个方法的内部有一个变量s持有一个对象( )的强引用,那么这个变量s保存在栈中,而真正的引用内容( )保存在堆中。当这个方法运行完成后就会退出方法栈,则引用s也会被销毁,这个 就可能会在之后的一次GC中回收。但是当这个s是全局变量时,就需要在不再使用这个对象时将引用s赋值为null,也就是消除与 对象之间的强引用,因为有强引用关联的对象是不会被垃圾回收的。

下面看另一个例子:

A a = new A();
B b = new B(a);
a = null;

这里a和b都持有一个对象的强引用,当执行 a = null 时, a 不再持有 A 的强引用。讲道理,A 已经该被回收了。但是这里a = null 时,A 对象不满足被回收的条件,因为还有一个B对象持有其强引用,这时候就会造成内存泄漏。

再看另一个会导致内存泄漏的例子:

public static ArrayList< > list = new ArrayList< >();
public void stackOverflowTest(   ){
    list.add( );
      = null;
}

GC回收的是不可达对象,但是,在这个静态集合类对象中,持有了对象的强引用,但却有可能其中的某些对象已经不再使用了,所以当非静态对象被静态变量持有强引用的时候,最容易发生内存泄露。

在方法中从list获取到对象后赋值给一个变量,使用完之后将这个变量设置为null并不会释放 引用的对象,因为list中还是持有对象的强引用。这时就造成了内存泄漏。

小结

所以小结一下强引用的特点:

  • 强引用就是最普通的引用
  • 可以使用强引用直接访问目标对象
  • 强引用指向的对象在任何时候都不会被系统回收
  • 强引用可能会导致内存泄漏
  • 过多的强引用会导致OOM
收藏 打印