又是一个被讲烂的东西,但是我还是总结一下,日后也可以自己看。
一、强引用
A a = new A(); a是强引用,new A();是对象。我们99%都是用这样形式,不多说,不举例。
二、软引用
软引用是说当内存不足时,也就是快oom之前,它会去把只有软引用引用的对象删除。例子如下:
结果如下:
三、弱引用
弱引用是说当第一次GC时候,删除只有弱引用引用的对象。例子如下:
结果如下:
四、虚引用(幽灵引用)
虚引用在任何时间都可能被删除,而且无论何时使用get方法都会返回null。他必须搭配RefrenceQueue使用,除了虚引用,软引用和弱引用都可以使用RefrenceQueue,而且用法都一样。这里就用虚引用做例子。例子如下:
结果如下:
五、threadlocal之oom
很多同行发博客我觉得已经失去了初心,我认为这是一个做技术人最纯粹的东西,但是现在很多人没有搞清楚或者复制别人的贴子,也许这也是大家认为谷歌比百度好的原因,但我不管环境怎么样,我的文章一定是原创,一定是我验证过的。
threadlocal里有个threadlocalmap,这个map自定义了一个entry,这个entry key是弱引用,value是threadlocal的值。
1、如果你用如下方式用threadlocal(我们大多数也是这么用的,阿里的java开发规范也是建议这么用的)
这里threadlocal是一个静态私有的成员变量,我们之前有说过弱引用只有当对象只有弱引用时候才会被GC清除,那么这样写就是有一个强引用,那么就不会出现很多文章说的出现key为null,value有值的entry。但是这样也会oom,比如线程太多,每个线程放到threadllocal里数据太大,也会oom。这里是oom第一个原因。
2、如果采用私有变量,那么会出现网上大部分文章说的key为null,从而导致oom的情况
原因解释:这里设置了threadlocal并且赋了值,但是他没有强引用。那么当第一次GC,时候entry里的key会被清空,value保留值。但是仅仅这样也是不会oom,还要有2个条件。
①就是所运行的线程不能结束,因为线程结束threadlocalmap也没了,自然不会oom。
②线程运行过程中不再执行set、get、remove命令
当线程运行过程中发生了GC,那么会留下一个空key的entry。并且没有执行set、get、remove,因为这3个命令都会清空key为null的entry。当满足这两个条件,请求线程再多一点,就会出现oom了。