1,833   Java

关于 equals和hasCode,上一遍文章有说过了,http://www.luckybird.me/java-%E5%85%B3%E4%BA%8Ehascode%E5%92%8Cequals.html

下面说,equals和hasCode导致内存泄露的现象。

1,缺少equals和hasCode,默认hasCode采用内存地址,使得散列类型变量比如HashMap重复保存相同的对象,占用额外的内存。
比如下面代码,重复保存map.put(new Key(“dummyKey”), “value”),其实是相同的value

import java.util.HashMap;
import java.util.Map;

public class JavaTest {

 public static void main(String[] args) {
  Map map = new HashMap(1000);

  int counter = 0;
  while (true) {
       // creates duplicate objects due to bad Key class
	  for(int i = 100;i>0;i--){
		  map.put(new Key("dummyKey"), "value");
	  }
  
   counter++;
   if (counter % 1000 == 0) {
    System.out.println("map size: " + map.size());
    System.out.println("Free memory after count " + counter
      + " is " + getFreeMemory() + "MB");

    sleep(1000);
   }

    
  }
 }

 // inner class key without hashcode() or equals() -- bad implementation
 static class Key {
  private String key;

  public Key(String key) {
   this.key = key;
  }

 }

 //delay for a given period in milli seconds
 public static void sleep(long sleepFor) {
  try {
   Thread.sleep(sleepFor);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

 //get available memory in MB
 public static long getFreeMemory() {
  return Runtime.getRuntime().freeMemory() / (1024 * 1024);
 }

}

运行结果,内存不断被额外消耗,最终导致内存不足

map size: 100000
Free memory after count 1000 is 170MB
map size: 200000
Free memory after count 2000 is 158MB
map size: 300000
Free memory after count 3000 is 151MB
map size: 400000
Free memory after count 4000 is 137MB
map size: 500000
Free memory after count 5000 is 130MB
map size: 600000
Free memory after count 6000 is 123MB
map size: 700000
Free memory after count 7000 is 116MB
map size: 800000
Free memory after count 8000 is 93MB
map size: 900000
Free memory after count 9000 is 87MB

2,通过remove销毁散列类型变量中的对象不成功,无用对象依然占用内存,导致内存泄露
remove对象时会根据hasCode去查找,如果hasCode不存在,就不会接着进行删除对象了。
如果hasCode是根据对象属性创建的,当对象属性改变时,那么hasCode也会更新,这么remove时就找不到原来的对象了,即remove失败,原对象还占用内存


import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

public class JavaTest {
	public static void main(String[] args){
		HashSet set = new HashSet();
		RectObject r1 = new RectObject(3,3);
		RectObject r2 = new RectObject(4,4);
		RectObject r3 = new RectObject(5,5);
		set.add(r1);
		set.add(r2);
		set.add(r3);
		
		System.out.println("before edit");
		System.out.println("before edit r1.hashCode:"+r1.hashCode());
/*		for(RectObject i : set){
			System.out.println("set:"+i+",x,"+i.getX()+",y,"+i.getY());
		}*/
		r1.setX(6);
		System.out.println("after edit");
		System.out.println("after edit r1.hashCode:"+r1.hashCode());
/*		for(RectObject i : set){
			System.out.println("set:"+i+",x,"+i.getX()+",y,"+i.getY());
		}*/
		System.out.println("before remove set.size:"+set.size());
		set.remove(r1);
		System.out.println("after remove set.size:"+set.size());
		System.out.println("after remove r1.hashCode:"+r1.hashCode());
		
/*		for(RectObject i : set){
			System.out.println("set:"+i+",x,"+i.getX()+",y,"+i.getY());
		}*/
		
	}

}



class RectObject {
	public int x;
	public int y;
	
	public RectObject(int x,int y){
		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;
		final RectObject other = (RectObject)obj;
		if(x != other.x){
			return false;
		}
		if(y != other.y){
			return false;
		}
		return true;
	}
}

运行效果如下:

before edit
before edit r1.hashCode:1057
after edit
after edit r1.hashCode:1150
before remove set.size:3
after remove set.size:3
after remove r1.hashCode:1150



Leave a Reply

Your email address will not be published. Required fields are marked *