一、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 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 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