System.gc()
-
在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存
-
然而System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。
-
jvm实现者可以通过System.gc()调用来决定jvm的GC行为。而一般情况下,垃圾回收是自动进行的,无须手动触发,否则就太过于麻烦了。在一些特殊情况下,比如我们在编写一个性能基准,我们可以在运行之前调用System.gc()
-
方法3没有GC,方法4GC。因为变量虽然只在代码块里面起作用,但是在方法3的局部变量表里还存在着,而方法4局部变量表里,value覆盖了buffer
内存溢出
内存泄露
STW---Stop the World
- 指的是GC事件发生过程中,会产生应用程序的卡顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW
- 可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。
- 分析工具必须在一个能确保一致性的快照中进行
- 一致性指整个分析期间整个执行系统看起来像被冻结在某个时间点上
- 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性无法保证
- 可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。
- 被STW中断的应用程序线程会在完成GC之后恢复,频繁中断会让用户感觉像网速不快造成电影卡带一样,所以我们需要减少STW的发生
- STW和采用哪款GC无关,所有的GC都有这个事件【只要用可达性分析算法的GC】
- 哪怕是G1也不能完全避免stop-the-world情况发生,只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能地缩短了暂停时间
- STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户造成的工作线程全部停掉
- 开发中不要用System.gc()会导致STW
垃圾回收的并发与并行
安全点和安全区域
- 程序执行时,并非能在所有的地方都能停下来GC,只有在特定的位置停顿下来开始GC,这些位置称为安全点(Safepoint)
- Safe Point 的选择很重要,不能太多,不能太少。太多会导致程序频繁停顿,影响程序性能,太少会导致GC等待的时间太长
- 通常会选择一些执行时间较长的指令作为 SafePoint,比如方法调用,循环跳转和异常跳转等
- 如何在GC开始时,保证所有线程都跑到最近的安全点停下来?
- 抢占式中断(现在没有虚拟机用了):先中断所有线程,如果有线程不足安全点,恢复那些线程,让他们跑到安全点
- 主动式中断:设置一个中断标志(表示要GC了,需要中断了),线程到达安全点会轮询这个标志,如果这个标志为真,线程就会自己中断挂起,如果为假,线程就继续执行
- 安全区域:在线程处于Sleep或Blocked等不执行的状态时,无法响应jvm的中断请求,无法走到安全点去中断挂起。jvm也不会等待线程唤醒。这时就需要安全区域了。安全区域指的是在一段代码片段中,对象的引用关系不会发生变化,在这个区域中的任何位置开始GC都是安全的。可以把安全区域看成被扩展了的安全点
- 实际执行时:
- 1.当线程运行到SafeRegion的代码时,首先标识这个线程进入了SafeRegion,如果这段时间内发生GC,jvm会忽略标识为SafeRegion状态的线程【应该讲错了,应该不会忽略】
- 2.当线程即将离开安全区域时,会检测GC是否已经完成,如果完成了,则继续执行。如果没有完成,线程必须等待直到收到可以安全离开安全区域的信号为止
引用【强软弱虚!】
- 强引用------不会被回收
- 使用场景:平时new对象时,使用的就是强引用,普通程序99%都是强引用
- 一个普通对象,如果没有被引用,或者超出了引用的作用域,或者强引用显式赋值为null,就可以当作垃圾收集了
- 可以直接访问目标对象
- 是造成内存泄露的一个原因
- 软引用------直到不回收直到报OOM才会回收(内存够的时候,GC了也不回收)
- 使用场景:缓存
- 只被软引用关联着的对象,在系统将要发生OOM前,会把这些对象列进回收范围之中进行第二次回收。如果回收之后内存还是不够,就OOM
- 垃圾回收器在某个时刻决定回收软可达的对象时,会清理软引用,并可选地把引用放到一个引用队列
- 获取对象是:userSoftRef.get()
- 弱引用------只要GC就会被回收
- 使用场景:缓存,比如用WeakHashMap做缓存
- 虽然一GC就会被回收,但是GC线程优先级很低,所有不一定能很快地发现持有弱引用的对象,可以存活较长时间
- 软引用弱引用都很适合保存那些可有可无的缓存数据。因为它可以在内存多的时候可以存活较长时间,加速系统,内存不够的时候也可以被回收,不被占用
- 虚引用------有了像没有一样,唯一目的(不是作用)是用来通知对象被回收了
- 也称为"幽灵引用""幻影引用",是所有引用中最弱的一个
- 对象有了虚引用也不会影响它的GC过程,有没有都一样
- 虚引用不能单独使用,也不能通过虚引用获得被引用的对象。用get()方法得到结果为null
- 为一个对象设置虚引用的唯一目的在于跟踪垃圾回收过程。比如能在这个对象被GC时收到一个系统通知
- 虚引用必须和引用队列一起用。因为当这个对象被GC时,这个虚引用会放到引用队列里。
- 由于虚引用可以跟踪对象的回收时间,因此也可以将一些资源释放操作放在虚引用中执行和记录
- 终极器引用