内存溢出与内存泄漏区别
Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽);
而Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
内存溢出,这个好理解,说明存储空间不够大。就像倒水倒多了,从杯子上面溢出了来了一样。
内存泄漏,原理是,使用过的内存空间没有被及时释放,长时间占用内存,最终导致内存空间不足,而出现内存溢出。
内存泄漏包含内存溢出
用static时候 会引发这个问题哦 还有IO流问题
举个栗子:
bean:
public class ReflectPoint { public int x; public int y; public ReflectPoint(int x, int y) { this.x = x; this.y = y; } }
测试:
存进去对象后,修改属性的值。修改完毕后remove
注意对于List的存储
引用的存储:
顺序存储
好多个引用变量引用的同一个对象
Set的存储:
存储的时候,先进行比价。如果有了就不存储了。引用都是相等的就不放啦~ 如果希望相等就重写equals方法
补充HashCode方法与HashSet类
如果想查找一个集合汇总是否包含某个对象,大概的程序代码是这样呢? 你通常是逐一取出每个元素与要查找的对象进行比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息。如果一个集合中有很多元素,注意比较非常恐怖。
有人发明了哈希算法来提高从集合中查找元素的效率。这种方式将集合分成若干个存储区域,每个对象可以计算进出一个哈希值,可以通过哈希值进行分组,每个分组对应某个存储区域,根据一个对象的哈希值就可以确定该对象应该存储在哪个区域。
HashSet就是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余数的方式对哈希值进行分组和划分对象的存储区域。Object类中定义了一个hashCode()方法来返回每个Java对象的哈希值。当从HashSet集合中查找某个对象时候,Java系统首先调用对象的hashCode()方法获取该对象的哈希值。然后根据哈希值找到相应存储区域。最后去除该存储区域内的每个元素与该对象进行equals比较。这样就不用遍集合中的所有元素就可以得到结论。可见HashSet集合具有很好的对象检索性能。
注意啊 当一个对象被存储近HashSet集合以后,就不要修改这个对象那些参与计算哈希值的字段了,否则对象修改后哈希值与最初存储近HashSet集合中时的哈希值就不同了,在这种情况下,即使contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果。这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
Bean:
package com.toov5.test; import java.util.Objects; public class ReflectPoint { public int x; public int y; public ReflectPoint(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ReflectPoint that = (ReflectPoint) o; return x == that.x && y == that.y; } @Override public int hashCode() { return Objects.hash(x, y); } }
测试:
public class test1 { public static void main(String[] args) { Collection collection = new HashSet<ReflectPoint>(); ReflectPoint reflectPoint1 = new ReflectPoint(1, 2); ReflectPoint reflectPoint2 = new ReflectPoint(3, 4); ReflectPoint reflectPoint3 = new ReflectPoint(1, 2); collection.add(reflectPoint1); collection.add(reflectPoint2); collection.add(reflectPoint3); // reflectPoint1.y=7; //修改完后哈希值就改了 collection.remove(reflectPoint1); System.out.println(collection.size()); System.out.println(collection); } }
结果:
修改参数hashCode的属性值:
public class test1 { public static void main(String[] args) { Collection collection = new HashSet<ReflectPoint>(); ReflectPoint reflectPoint1 = new ReflectPoint(1, 2); ReflectPoint reflectPoint2 = new ReflectPoint(3, 4); ReflectPoint reflectPoint3 = new ReflectPoint(1, 2); collection.add(reflectPoint1); collection.add(reflectPoint2); collection.add(reflectPoint3); reflectPoint1.y=7; //修改完后哈希值就改了 collection.remove(reflectPoint1); System.out.println(collection.size()); System.out.println(collection); } }
运行结果:
这样频繁的操作,有些对象删除不掉,会造成内存泄露哦。哈希值在某个区域里面。以为删掉了~~
对象不用了却一直在,占用着内存空间。