HashMap内存泄露

您所在的位置:网站首页 java检测内存溢出 HashMap内存泄露

HashMap内存泄露

2023-04-15 17:03| 来源: 网络整理| 查看: 265

背景

HashMap对于Java开发人员来说,应该是一种非常非常熟悉的数据结构了,应用场景相当广泛。 本文重点不在于介绍如何使用HashMap,而是关注在使用HashMap过程中,可能会导致内存泄露的情况,下面将以示例的形式展开具体介绍。

注意:理解本文的前提需要先熟悉HashMap原理。 为了更快的看到java.lang.OutOfMemoryError: Java heap space,我们可以配置下IDEA的JVM参数,简单配置下初始堆和最大堆参数为3M,-Xmx3m -Xms3m,如下图

场景一:重写hashcode、equals,put同一个对象,但是put前成员属性值发生了改变

直接上示例代码:

public class Test { public static void main(String[] args) { Map map = new HashMap(); Person p = new Person("0", 10); for (int i = 0; i < 50000; i++) { p.setName(String.valueOf(i)); map.put(p, 1); System.out.println(map.size()); } System.out.println("end."); } } class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj instanceof Person) { Person personValue = (Person) obj; if (personValue.getName() == null && name == null) { return true; } return personValue.getName() != null && personValue.getName().equals(name); } return false; } @Override public int hashCode() { return name.hashCode(); } }

直接点击运行,查看结果,发现当put第49153个对象时,报了java.lang.OutOfMemoryError: Java heap space

49152 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.HashMap.resize(HashMap.java:703) at java.util.HashMap.putVal(HashMap.java:662) at java.util.HashMap.put(HashMap.java:611) at app.Test.main(Test.java:23)

结果分析:本来,HashMap put同一个对象,理论上是会覆盖的,不会导致内存泄露,这里之所以出现这种情况,主要是因为我们put的并不是同一个对象(重写了hashcode和equals方法,且hashcode发生了改变),然后一直put,就导致对象越来越多,最终触发OutOfMemoryError。

场景二:没有重写hashcode、equals,put的对象每次都是new出来的

直接上示例代码:

public class Test { public static void main(String[] args) { Map map = new HashMap(); for (int i = 0; i < 500000; i++) { map.put(new Person("0", 10), 1); System.out.println(map.size()); } System.out.println("end."); } } class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

同样,直接点击运行,查看结果,发现也报了java.lang.OutOfMemoryError: Java heap space

39951Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at java.nio.CharBuffer.wrap(CharBuffer.java:373) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.PrintStream.newLine(PrintStream.java:545) at java.io.PrintStream.println(PrintStream.java:737) at app.Test.main(Test.java:21)

结果分析:这个没啥好说,Object默认的hashcode对于new出来的对象都是不同的,然后一直put,就导致对象越来越多,最终触发OutOfMemoryError。

总结

当使用HashMap执行put操作的时候,如果你期望的结果是覆盖这个key,那么你要再三确认put的时候,key对象的hashcode有没有发生变化,否则可能会有意想不到的结果; 建议,当想要使用对象作为HashMap的key时,可以考虑使用不可变对象作为HashMap的key,如常用的String类型,或者确保使用不可变的成员属性来生成hashcode;



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3