Java内存在分配和回收的过程中会产品很多的问题,下面来说一说可能会产生的问题。
1、垃圾处理
import java.util.EmptyStackException; public class test { private Object[] elements = new Object[10]; private int size = 0; public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } }
上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的,没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无用,无法回收。
但是就是存在这样的东西也不一定会导致什么样的后果,如果这个堆栈用的比较少,也就浪费了几个K内存而已,反正我们的内存都上G了,哪里会有什么影响,再说这个东西很快就会被回收的,有什么关系。下面看两个例子。
import java.util.Stack; public class test3 { public static Stack<Object> s = new Stack<>(); static { s.push(new Object()); s.pop(); // 这里有一个对象发生内存泄露 s.push(new Object()); // 上面的对象可以被回收了,等于是自愈了 } } } }
因为是static,就一直存在到程序退出,但是我们也可以看到它有自愈功能,就是说如果你的Stack最多有100个对象,那么最多也就只有100个对象无法被回收其实这个应该很容易理解,Stack内部持有100个引用,最坏的情况就是他们都是无用的,因为我们一旦放新的进去,以前的引用自然消失!
内存泄露的另外一种情况:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。
import java.util.HashSet; import java.util.Set; public class HashSetTest { public static void main(String[] args) { Set<Person> set = new HashSet<Person>(); Person p1 = new Person("唐僧", "pwd1", 25); Person p2 = new Person("孙悟空", "pwd2", 26); Person p3 = new Person("猪八戒", "pwd3", 27); set.add(p1); set.add(p2); set.add(p3); System.out.println("总共有:" + set.size() + " 个元素!"); // 结果:总共有:3 个元素! p3.setAge(2); // 修改p3的年龄,此时p3元素对应的hashcode值发生改变 set.remove(p3); // 此时remove不掉,造成内存泄漏 set.add(p3); // 重新添加,居然添加成功 System.out.println("总共有:" + set.size() + " 个元素!"); // 结果:总共有:4 个元素! for (Person person : set) { System.out.println(person); } } }
package test6; public class Person { private String username; private String password; private int age; public Person(String username, String password, int age){ this.username = username; this.password = password; this.age = age; } public String getUsername(){ return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } public String toString() { return this.username+"-->"+this.password+"-->"+this.age; } }输出结果如下: