System.gc()的理解
- 在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存;
- 然而System.gc()调用附带一个免费声明,无法保证对垃圾收集器的调用;
- JVM实现者可以通过System.gc()调用来决定JVM的GC行为。而一般情况下,垃圾回收是自动进行的,无须手动触发,否则就太过于麻烦了;
System
public static void gc() {
Runtime.getRuntime().gc();
}
public static void runFinalization() {
Runtime.getRuntime().runFinalization();
}
public class SystemGcTest {
public static void main(String[] args) {
new SystemGcTest();
System.gc();
//提醒JVM的垃圾收集器执行gc,但是不确定是否马上执行gc
System.runFinalization();
//强制调用失去引用对象的finalize()方法
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("SystemGcTest重写了finalize()方法");
}
}
内存溢出和内存泄漏
JavaDoc中对OutOfMemoryError的解释是:没有空闲内存,并且垃圾收集器也无法提供更多内存。
首先说没有空闲内存的情况:说明Java虚拟机的堆内存不够:原因有二:
- Java虚拟机的堆内存设置不够,我们可以通过参数-Xmx、-Xms来调整;
- 代码中创建了大量的大对象,并且长时间不能被垃圾收集器收集(存在引用)
这里面隐含着一层意思是,在抛出OOM之前,通常垃圾收集器会被触发,尽其所能去清理空间。
- 例如,在引用机制分析中,涉及到JVM会去尝试回收软引用指向的对象;
当然,也不是在任何情况下垃圾收集器都会被触发的。
- 比如,我们去分配一个超大对象,类似一个超大数组超过堆的最大值,JVM可以判断出垃圾收集并不能解决这个问题,所以直接抛出OOM。
严格来说,只有对象不会再被程序使用到了,但是GC又不能回收它们的情况,才叫内存泄漏。
举例:
1、单例模式
单例的生命周期和应用程序是一样长的,所以单例程序中,如果持有对外部对象的引用的话,那么这个外部对象是不能被回收的,则会导致内存泄漏的产生。
2、一些提供close的资源未关闭导致内存泄漏
数据库连接、网络连接和IO连接必须手动close,否则是不能被回收的。
Stop The World
垃圾回收的并行与并发
程序中的并发与并行。
并发(Concurrent):并发并不是真正意义上的同时进行。
安全点与安全区域
安全点:程序执行时并非在所有地方都能停顿下来开始GC,只有在特定的位置才能停顿下来开始GC,这些位置称为"安全点(Safe point)"。
如何在GC发生时,检查所有线程都跑到最近的安全点停顿下来呢?
- 主动式中断
设置一个中断标志,各个线程运行到Safe point的时候主动轮训这个标志,如果中断标志为真,则将自己进行中断挂起。
Java中的引用
我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存中;如果内存空间在进行垃圾收集后还是很紧张,则可以抛弃这些对象。
在JDK1.2版本之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用强度依次逐渐减弱。
除了强引用外,其他三种引用均可以在java.lang.ref包中找到它们的身影。
Reference子类只有终结器引用是包内可见的,其他三种引用类型都是public,可以在应用程序中直接使用。
- 强引用:最传统的引用的定义,是指在程序代码中普遍存在的引用赋值,即类似Object obj = new Object(),这种引用关系。无论任何情况下,只要强引用关系还在,垃圾收集器就永远不会回收掉被引用的对象;
- 软引用:在系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出OOM;
- 弱引用:被弱引用关联的对象只能生存到下一次垃圾收集之前,当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被弱引用关联的对象;
- 虚引用:一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。
强引用
强引用—不回收
软引用
软引用—内存不足则回收
第一次回收指:回收不可达对象。
弱引用
弱引用—发现即回收
WeakReference<String> reference = new WeakReference<>(new String("123"));
System.out.println(reference.get());
//123
System.gc();
System.out.println(reference.get());
//null
虚引用
虚引用—对象回收跟踪