System.gc()的理解
在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显示的触发Full GC,同时对老年代和新生代进行回收,尝试释放被废弃对象占用的内存
注意:System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用
内存溢出的分析
由于GC一直处于发展中,一般来说,除非应用占用的内存增长速度太快,导致垃圾回收跟不上内存消耗的速度,否则不太容易出现OOM的情况
大多数情况,GC会进行各个年龄段的垃圾回收,实在不行,就独占式的Full GC,这时候会回收大量内存,供应用继续使用
javadoc对oom的解释:没有空闲内存,并且垃圾收集器也无法提供更多内存
在内存溢出之前,通常垃圾收集齐器是会被触发过的,尽可能去清理空间
1.例如在引用机制分析中,涉及到JVM会去尝试回收软引用指向的对象
2.java.nio.BIts.reserveMemory()方法中,我们能清楚的看到,System.gc()会被调用,以清理空间
不过,垃圾收集器不是一定会被触发的,比如如果是分配一个超大对象,都已经超出了堆的最大空间,JVM判断垃圾收集解决不了这个问题,就会直接抛出OOM
内存泄漏的分析
也称作“存储渗漏”。严格来说,只有对象不会再被程序用到里,但是GC又不能回收他们的情况,才叫内存泄漏
但是实际情况中,会有一些不好的代码习惯导致对象的生命周期变得很长甚至导致OOM,也可以叫做宽泛意义上的内存泄漏
内存泄漏本身不会引起系统奔溃,但是这是一个滴水穿石的过程,最终导致内存被耗尽,出现OOM
错误例子分析
1.基于引用计数算法引起的循环引用不适合用来当例子,因为我们的jvm没有采用引用计数算法,所以不会出现这种情况
正确例子分析
1.比如将本应该定义在方法中的局部变量定义为成员变量,就会导致生命周期变长
2.单例模式下 单例的生命周期和应用程序是一样长的,所以单例中,如果持有对外部对象的引用的话,那么这个外部对象就不能被回收了,导致内存泄漏。
3.一些提供close的资源未关闭导致内存泄漏,比如数据库连接啊(dataSource.getConnection(),网络连接(socket),IO流等)