前言
众所周知,WeakHashMap
中的key
是弱引用,如果再使用之后没有及时remove
掉这个key,那么当GC时key就可能会被回收,导致key对应的value对象占用的内存无法回收进而导致内存泄漏,如果有大量的key可能会导致内存溢出、频繁FullGC等问题。
说了这么多导致内存泄漏是因为WeakHashMap
的key
是弱引用从而导致内存泄漏,但是HashMap
的key是强引用,也会导致内存泄漏吗?
Java中的四种引用
先简单了解一下Java中的四种引用分别是什么
-
强引用
如果一个对象是强引用,
GC
不会回收该对象(在该对象可达时),就算发生内存溢出也不会回收该对象。一般手动new
出来的对象都是强引用什么时候回收强引用对象呢?平常写代码中那么多
new
的对象怎么没有发生内存溢出呢平常代码中有大量的例如:Objedt obj = new Object() 这种手动创建的对象既然都是强引用,不会被回收,JVM还不是分分钟爆炸?
其实,强引用对象也是会被回收的,根据GC回收的算法—可达性分析算法进行判断,当一个对象不可达时就会被回收(不可达就不继续展开啦),或者手动将
obj=null
,也会回收该对象。因为obj指向这个new
出来的对象,所以是可达的对象不会被回收,但是obj
一般是在栈中,当前线程执行完成,该方法栈就会被回收,所以obj也会被回收,进而导致堆中该对象没有引用可达而被回收。 -
软引用
如果堆内存空间充足,则一般GC时不会回收软引用对象,只有在堆内存空间不足的时候才会回收软引用内存空间的对象。使用场景:(和弱引用相同的作用)一般可以用作本地缓存,防止缓存中的数据量太大导致内存溢出
-
弱引用
无论堆内存空间是否充足,在每次GC的时候都可能会对弱引用对象进行回收。
-
虚引用
虚引用,正如其名,对一个对象而言,这个引用形同虚设,有和没有一样,简单来说虚引用就相当于没有引用。它的作用就是在GC的时候会发出一个系统通知
HashMap内存泄漏场景
-
HashMap的
put
方法分析先分析一下HashMap的put/get,做好前戏~
HashMap
的put
方法在保存数据的时候会根据**key
计算出来hash值**,然后根据hash值获取到数组的下标的位置,没有发生hash冲突就只直接保存,如果发生hash冲突则形成链表。get
方法是根据key的hash值得到数组的下标,然后直接获取或者遍历链表并调用equals
方法来获取数据。
第一种:内存泄漏代码
-
下面的代码会导致内存泄漏吗
class Person { String name; int age; //省略getter/setter方法 ... } HashMap<Person, Integer> map = new HashMap<>(); Person gay = new Person("gay伦", 18); Person yase = new Person("亚瑟", 10); Person timo = new Person("提莫", 11); // 保存 map.put(gay,