1.System.gc方法的理解
System.gc会显示触发Full GC;同时对老年代和新生代进行回收,尝试释放被丢弃对象占用的内存;
但无法保证对垃圾收集器的调用,也可能不调用;
System.runFinalization强制调用失去引用的对象的finalize方法
例子:
从字节码来看,局部变量表中buffer占用索引1的位置,垃圾回收,只是把指向去掉为清除值;
局部变量表的长度还是2;
局部变量表的长度还是2,而索引1的位置被value覆盖,buffer的引用不存在了,所以垃圾回收会释放掉buffer
方法5再次调用GC后就会被垃圾回收了;
原因第一次GC时,buffer指向被去掉,但引用还在;第二次GC时;buffer引用为null,所以就被回收了;
2.内存溢出与内存泄露
2.1内存溢出
OOM:是没有空闲内存空间,GC后还是没有空闲的内存空间,就会报OOM;
OOM报出时,一般都会触发一次垃圾回收;
但若分配的对象特别大,超出整个堆的大小,则直接报OOM;
2.2内存泄露
内存泄露:只有对象不会再被程序用到了,但是GC又不能回收他们的情况;
多个引用释放后,但有一个引用还未释放,则不会回收
内存泄露举例:
3.Stop The World
STW是必须发生的;
例子:
4.垃圾回收的并行与并发
4.1并发Concurrent
同一个CPU在一个时间段中有多个程序在运行;
4.2并行Parallel
多个CPU上同时运行多个程序,互不干扰;
两者对比:
垃圾回收的并发与并行
并行:多个垃圾回收线程同时运行;
并发:用户线程与垃圾收集线程同时执行,但不一定是并行,而是交替执行
5.安全点与安全区域
5.1安全点Safepoint
安全点选择:如果太少则导致GC等待的时间太长,若太频繁则导致运行时的性能问题。
所以选择执行时间较长的指令作为SafePoint,如方法调用,循环跳转和异常跳转等;
采用主动式中断:轮询查询中断标志,若是真则将自己进行中断挂起。
5.2 安全区域
但当程序不执行的时候,如sleep或blocked状态时,这时线程无法响应JVM的中断请求,这时需要安全区域来解决。
只要落到安全区域的时候,即对象的引用关系不会发生变化,都可以GC。
实际执行时:
6. JAVA中的几种不同的引用
前提:引用关系还在,若引用关系不在了,则什么时候都回收。
强应用:死也不回收,即出现OOM也不回收;
软引用:内存不足即回收,内存足就不回收;
弱引用:只要垃圾收集,都要回收;发现即回收;
虚引用:标识对象被收集器回收之前,收到一个系统通知;对象回收跟踪;
强引用90%是;软、弱引用缓存场景中使用;虚引用跟踪对象回收使用;
6.1 强引用(Strong Reference)-不回收
对象的三种状态:
可触及的:从根节点开始,可以到达这个对象;
可复活的:对象的所有引用都被释放,但是对象有可能在finalize中复活;
不可触及的:对象的finalize被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为finalize只会被调用一次。
强引用是可触及的;软引用、弱引用和虚引用是软可触及、弱可触及和虚可触及的。
强引用是造成Java内存泄露的主要原因之一;
例子:强引用
还能打印出str1,因为即使str是null,但str1还会指向字符串常量池,是强引用,所以未回收。
6.2软引用(Soft Reference)--内存不足即回收
第一次回收:对不可触及的对象进行回收;
第二次回收:对可触及的软引用进行回收;
OOM:与非强引用没关系;只与强引用有关系;
软引用适用场景:高速缓存
软引用:当内存够时,不会被回收;当内存不够时,会被回收;
弱引用:只要GC都会被回收;
例子:
将堆内存设置为10M;2:1年轻代与老年代比例;4:6M
6.3弱引用(Weak Reference)--发现即回收
软引用、弱引用都适合来保存哪些可有可无的缓存数据;
三级缓存:内存->本地->网络
开发中使用WeakHashMap?
这个HashMap在内存不够时会自动回收;
6.4虚引用(Phantom Reference)--对象回收跟踪
6.5 终结器引用(Final reference)