JVM之垃圾回收的相关概念
1.System.gc()的理解
-
调用该方法会触发Full GC。
-
该方法附带个免责声明,无法保证对垃圾收集器的调用时间,意思就是不是你一调用该方法就进行垃圾回收。
-
尽量少用,一般在特殊情况下调用,比如性能测试之前。
-
局部变量表中的数据不会立马失效,而是新来的变量覆盖了这个Slot槽之后 才会被回收。
2.内存溢出
-
基本解释:
- 没见有空闲内存,并且垃圾收集器也无法提供更多内存。(GC之后还没有内存)。
- java虚拟机堆内存不够的原因
- Java虚拟机的对内存设置不够。
- 代码中创建大量大对象,并且长时间不能被垃圾收集器收集(存在引用)
-
OOM之前,通常垃圾收集器会被触发,尽可能多的清理出空间
- 尝试回收软引用指向的对象等。
-
特殊情况下,为一个大对象分配内存超过了堆空间的最大内存,不会进行垃圾回收,直接报OOMError。
3.内存泄漏
- 严格来说 只有对象不会再被程序用到了,但是GC又不能回收它们的情况,才叫内存泄漏。
- 内存泄漏可能会导致OOM。
- 内存泄漏会慢慢的蚕食内存,直到内存被消耗殆尽,最终报OOMError。
- 内存泄漏的相关例子:
1.单例模式
***单例的声明周期和应用程序一样长 *** ,所以单例程序中,如果持有外部对象的引用,就会造成那个对象一直处于可达,不能被回收,就会导致内存泄漏。- Close的资源未关闭导致内存泄漏
数据库连接、网络连接、io。
- Close的资源未关闭导致内存泄漏
4.什么是STW
- 概念:
指的是GC事件发生过程中会产生应用程序的停顿。停顿产生时整个应用程序的线程都会被暂停,没有任何响应, 这个停顿就被称为 STW
- 例子
可达性分析算法中枚举根节点(GC Roots)会导致所有java执行的线程停顿。
- 分析的时候必须保证在同一个快照中进行,保持一致性
- 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性就无法保证
- 被STW中断的线程会在GC完成之后回复,(会有上下文切换消耗时间)。
- 所有的GC都会产生STW,只是暂停时间长短的问题,好的GC就应该尽可能的缩短STW的时间
5.垃圾回收中的并行与并发
- 并发(Concurrent)
- 在操作系统中是指一个时间段内几个程序(进程)都处于运行到运行完毕之间,且这几个程序都在同一个处理器运行。
- 并行并不是真正意义的“同时发生”,而是CPU把一个时间段划分成若干个时间片(几十ms),然后在这几个时间片中来回切换线程或进程,由于CPU处理速度非常快,只要时间间隔处理得当,用户就会感觉几个程序都在同时运行。
- 并行Parallel
- 当系统有一个以上CPU(内核),每个CPU同时执行不同的进程,而且两个进程之间不互相抢占资源,称为并行。
- 适合科学计算,后台处理,等弱交互场景。
- 二者比较
- 并发,指多个事情,在同一个时间段内发生。
- 并行,指多个事情,在同一个时间点发生。
- 并发的多个任务之间互相抢占资源。
- 并行的多个任务之间互不抢占资源。
- 垃圾回收中的并行(Parallel)
指多条垃圾回收的线程并行工作,用户线程处于等待状态。
- 并行的垃圾回收有,ParNew、Parallel Scavenge、Parallel Old
- 垃圾回收中串行(Serial)
- 单线程执行
- 如果内存不够,程序暂停执行,启动JVM垃圾回收器进行垃圾回收,垃圾回收完了,程序在启动运行。
- 垃圾回收中的并发(ConCurrent)
- 指用户线程和垃圾回收线程同时执行(有可能是并行执行,有可能是并发交替执行),垃圾线程执行回收时不会停顿用户线程。
- CMS、G1
6.安全点和安全区域
- 安全点(safePoint)
- 垃圾回收器只有在特定的位置才进行GC,这些位置就是 “安全点” 。
- 安全点的选择很重要,如果太少可能导致GC等待时间太久,然后进行GC的时候STW时间就会增加;如果太多GC就会很频繁,可能会导致运行时的性能问题。
- 如何在GC发生时,(为了一致性)检查所有线程都跑到最近的安全点停顿下来了?
- 抢先式中断:(目前没有JVM采用了)
- 首先中断线程。如果还有线程不在安全点,就恢复线程,让线程跑到安全点。(是其它线程在停,等待这个没有到达安全点的线程跑到安全点么?)
- 主动式中断:
- 设置一个中断标志,让各个线程运行到SafePoint的时候主动轮询这个标志,如果中断标志为真,则主动将自己中断挂起。
- 安全区域
- 指在一段代码片段中,对象的引用不会在发生变化,在这个区域中的任何位置都可以开始GC并且是安全的。
总结
- 不是执行System.gc()就立马进行垃圾回收的,它只是通知JVM进行垃圾回收,不能保证就立马执行。
- 内存溢出,就是内存不够用了;内存泄漏,是这块虚拟内存一直有引用指向,垃圾回收器无法对其回收,也没有使用这个引用指向,有点占着茅坑不拉屎的感觉。
- STW,就是为了保证GC的准确性,只有垃圾回收线程可以运行。在我正在数有多少个垃圾的时候,我在前面数着,你在后面丢着。数的肯定不准。
- 垃圾回收里的并发有点不一样,它指的是垃圾回收线程和用户线程可以同时执行,但是(线程和线程之间可以并行也可以并发)。
- 安全点为了保证只有到达某个点你猜能GC,安全区域怕你永远到不了那个点,就把这个点扩大个范围,让你GC