一、过期引用导致的内存泄露
注意:当对象不使用后将对象设置为null,这个时候虚拟机不一定释放该内存,至于什么时候释放由垃圾回收算法确定。
当对象不在使用时,而不回收有可能出现内存泄露的问题。在Effective Java里面有一条建议,消除过期的对象引用。
实例:JDK中栈的内存优化问题
1、消除过期对象引用的原因(出现内存泄露的原因):随着栈的增加,然后再收缩,从栈中出来的对象将不会被回收,即使程序不在引用这些对象。
因为,在栈的内部维护着这些对象的过期引用(过期引用就是永远不会被解除的引用)。
2、内存泄露过程:随着垃圾回收器的活动,或者说内存占用的不断增加,程序的性能变低会慢慢显示出来。在极端的情况下,程序很容易出现OOM的错误。
下面的程序模拟JDK中Stack的实现:
public class MyStack { private Object[] elements;// 栈用来装元素的 private int size = 0;// 栈的大小 private static final int DEFALT_INITIAL_CAPACITY = 16; public MyStack(){ elements = new Object[DEFALT_INITIAL_CAPACITY]; } /* * 入栈 */ public void push(Object e) { ensureCapacity(); } /** * 出栈 */ public Object pop() { if(size==0) throw new EmptyStackException(); return elements[--size]; } /** * 动态扩展栈的空间,确保栈中有足够的空间 */ private void ensureCapacity() { if(elements.length==size) { elements = Arrays.copyOf(elements, 2*size+1); } } }
二、hashCode与内存泄露:
public class MemoryLeakDemo { public static void main(String[] args) { Point p1 = new Point(1,2); Point p2 = new Point(3,4); Point p3 = new Point(3,6); Collection<Point> c = new HashSet<Point>(); c.add(p1); c.add(p2); c.add(p3); c.add(p1); System.out.println("原来的对象数量:"+c.size()); // p1.setX(5); c.remove(p1); System.out.println("处理后的对象数量:"+c.size());// 原来有三个对象,删除后还有两个,打开上面的注释后,变成三个。 } } class Point { private int x; private int y; public Point(int x, int y) { super(); this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Point other = (Point) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } }
原来有3个对象,删除后还有2个,打开上面的注释后,变成3个。为什么会对象删不掉呢?因为修改hashCode后,这个对象所在存储区域发生变化(哈希查找基本思路:通过计算对象的哈希码,然后进行哈希码分组,将对象存储到不同的区域,当需要对象时只需通过哈希码就可以确定对象属于哪个存储区域,从而加快了查找效率),执行remove方法后对象没有被删除,所以仍然是这么多元素。因为不用的对象占着内存不释放,所以出现了内存泄露的问题。那么,随着增删操作元素的次数不断增加,内存的耗用越来越大,从而导致程序异常结束。
时间: 2024-10-25 14:24:28