一、System.gc()
- 默认,通过System.gc() 或 Runtime.getRuntime().gc(), 会触发 Full GC
Full GC 会同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存
- 无法保证堆垃圾收集器的调用, 可以通过 重写finalize()来判断
- 一般情况下,垃圾回收自动进行,无须手动触发
特殊情况下,可以显示调用来做基准测试
二、内存泄漏/内存溢出
1. 内存溢出(OOM)
1. 应用程序占用的内存增长速度快,快速占用了JVM的所有内存
2. 进行一次独占式的 Full GC 操作后,回收大量内存
OOM: 没有空闲内存,并且垃圾回收器回收完后,依然无法提供更多内存
- 原因下面两个:
- Java虚拟机的堆内存设置不够
- 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集,存在被引用
2. 内存泄漏
- 严格来说, 只有对象不会再被程序用到了,但是GC又不能回收他们,才叫做内存泄漏
- 实际情况: 意外导致对象的生命周期变得很长甚至导致OOM,也可以叫做内存泄漏
比如类的static属性
- 内存泄漏可能会逐步消耗可用内存空间,直到耗尽所有内存,最终出现 OutOfMemory
example1: 单例模式
- 单例的生命周期和应用程序是一样长的,如果单例程序中持有对外部对象的引用,那么这个外部对象是不可能
被回收的,则会导致内存泄漏的产生
- 一些提供close的资源未关闭导致内存泄漏
比如socket,io,datasource等的链接,如果不手动close, 则是不能回收的
三、Stop The World
- Stop-The-World: 在GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点卡死的感觉,停顿就是STW
可达性分析算法中枚举根节点会导致所有java执行线程停顿
- 分析工作必须在一个能确保一致性的快照中进行
- 一致性指整个分析期间,整个执行系统看起来像是被冻结在某个时间点上
- 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性无法保证
被STW 中断的应用程序,会在完成GC 后回复,频繁中断会让用户感觉多个卡顿,所以需要减少STW的产生
1. STW和哪款GC无关,所有的GC 都有这个事件
2. 只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能的缩短了暂停时间
3. STW 是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停下来
4. 开发中不要用System.gc(), 会导致STW的发生
四、安全点和安全区域
程序执行时,并非在所有地方都能停顿下来开始GC,只有在特定的位置才能停顿下来开始GC
这些位置称为 安全点 - Safepoint
- Safe Point的选择很重要
- 如果太少,则等待GC的时间太长,就会导致oom
- 如果太多,则频繁的gc,导致运行时的性能问题
大部分指令的执行时间都非常短暂
通常会根据 “是否具有让程序长时间执行的特征”为标准
- 比如选择一些执行时间较长的指令作为 Safe Point,比如方法调用,循环跳转,异常跳转
安全区域: 在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的
可以把Safe Region看作是扩展了的 SafePoint
五、引用
- JDK 1.2后, Java对引用的概念进行了扩充
- 强引用,Strong Reference
- 软引用, Weak Reference
- 弱引用, Weak Reference
- 虚引用, Phantom Reference
- 强软弱虚,引用强度依次逐渐减弱
- 除强引用外,其他3种引用均可以在java.lang.ref包中找到,可以直接使用

- 上述不同的引用,均指的是在引用还存在的前提下,垃圾回收器是否会进行回收
1. 强引用
- 只要引用存在,那么就不会回收
- 强引用的对象是可触及的,只要引用没有断开,则永远不会被回收
- 强引用是内存泄漏的主要原因
- 强引用指的就是一般的那种通过new来创建出来的对象
2. 软引用
用来描述一些还有用,但并非必须的对象
- 软引用关联的对象,在系统将要发生oom的时候,会把软引用的对象,列入回收范围内进行
第二次回收
- 如果这次回收还没有足够的内存,才会抛出内存溢出
比如实现内存敏感, 高速缓存
垃圾回收器在某个时刻决定回收软可达的对象时,会清理软引用
可选的把软引用存放倒一个引用队列(Reference Queue中)
package com.nike.erick;
import java.lang.ref.SoftReference;
public class Demo01 {
public static void main(String[] args) {
Object obj = new int[1024];
SoftReference<Object> softReference = new SoftReference<>(obj);
obj = null;
System.out.println("Before GC" + softReference.get());
System.gc();
System.out.println("After GC" + softReference);
}
}
3. 弱引用
- 弱引用是用来描述那些非必须对象,只被弱引用关联的对象,只能生存到下一次垃圾收集发生为止
- 系统发生GC时候,只要发现弱引用,不管系统堆空间使用是否充足,都会回收掉只被弱引用关联的对象
- 存放缓存数据
- 弱引用相比软引用,更容易被发现和回收,速度更快
- WeakHashMap
package com.nike.erick;
import java.lang.ref.WeakReference;
public class Demo01 {
public static void main(String[] args) {
Object obj = new int[1024];
WeakReference<Object> weakReference = new WeakReference<>(obj);
obj = null;
System.out.println("Before GC" + weakReference.get());
System.gc();
System.out.println("After GC" + weakReference);
}
}
4. 虚引用
- Phantom Reference, 对象回收跟踪
- 一个对象是否有虚引用的存在,完全不会决定对象的生命周期。如果一个对象仅仅持有虚引用,那么它和没有引用几乎是一样的,随时都可能被垃圾回收器回收
- 它不能单独使用,也无法通过虚引用来获取被引用的对象。当试图通过虚引用的get方法获取对象时,总是null