Java中的引用类型
强软弱虚
强引用
(有新对象分配内存,但是GC回收没有回收掉强引用对象,那么内存不够时新对象不能分配)
软引用
:在堆(heap)中内存不够时,软引用才会被回收
假设堆内存是20M,而现在弱引用对象byte[]是10M,GC时不会被回收,在堆中创建另一个byte[]15M,内存不够,这时弱引用会被GC回收。
软引用适合缓存使用,因为当内存足够时它不会被回收,那么你想用时直接用,不用再加载一遍,当内存不够时就被GC回收,不占用空间。所以适合缓存使用。
弱引用
(GC回收一看到弱引用就会把它给回收了,不管内存够还是不够)没被GC回收前还是能拿到的
虚引用
回不回收都get不到对象(用来管理直接内存)
直接内存就说操作系统(OS)里的内存,从网络上获取的数据加载到直接内存,JVM管理的内存把它复制一份进来,这样比较不方便,所以直接在JVM内存中指向直接内存来引用。
JVM管理的是jvm里的内存,当虚引用对象被回收时,它指向的直接内存该怎么办,当虚引用对象被回收后,会被放到QUEUE(队列)中,JVM会观察QUEUE,如果里面有对象,就会做特殊处理,把直接内存给回收(相当于虚引用被回收时,给出一个信号,这个信号存在QUEUE中,通知JVM对直接内存做回收处理)
ThreadLocal
ThreadLocal 的对象在不同线程间相互隔离
线程2往ThreadLocal对象set (new person) 但是线程1是get不到的
tl 的set方法是把person存到map里,map的key是tl,value是person
Thread类里有一个map对象(ThreadLocalMap)threadLocals; ThreadLocal类的set方法是先获取当前线程thread,通过thread获取map;然后把tl作为key,要set的value 存进map结构
Spring里的@transactional事务注解和mybatis的分页处理用到了threadLocal
set方法的具体实现,先创建一个Entry (就是key,value对)
Entry是一个内部静态类,继承WeakReference(弱引用),super(k),调用weakReference方法创建弱引用对象,指向ThreadLocal tl
当强引用tl = null ,GC会把map弱引用的key回收了,key=null,但是value指向的数据(10M)因为key为null,所以不能被访问到,存在内存泄漏风险。所以要主动remove掉key为null的value(虽然源码里当我们调用set和get方法时会将key为null的value,remove掉,但是要是长时间不调用set、get方法,还是会存在内存泄漏的风险,所以要主动remove掉)
线程池里当一个线程被使用完,会自动清除threadlocals变量,保证map为空,防止线程在下一次被使用时出错