您的位置:首页 > 编程语言 > Java开发

java中是否存在内存泄漏?什么情况下才是内存泄漏?

2019-07-23 18:25 68 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/MengHen_0_0/article/details/97009448

简介

所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中。

内存泄漏的情况:

  1. java 中的内存泄露的情况:

长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致 不能被回收,这就是 java 中内存泄露的发生场景。

例一:
public class Stack {
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);
}
}
}
例二:
public class Bad{
public static Stack s=Stack();
static{
s.push(new Object());
s.pop(); //这里有一个对象发生内存泄露
s.push(new Object()); //上面的对象可以被回收了,等于是自愈了
}
}
}

上面的原理应该很简单,假如堆栈加了10个元素,然后全部弹出来,虽然堆栈是空的, 没有我们要的东西,但是这是个对象是无法回收的,这个才符合了内存泄露的两个条件:无 用,无法回收。

  1. 内存泄露的另外一种情况:

当一个对象被存储进 HashSet 集合中以后,就不能修改这个对 象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用 作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄露。

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class MemoryLeak {
@SuppressWarnings({ "unchecked", "rawtypes"})
public static void main(String[] args) {
Collection coll = new HashSet();
Map map1 = new HashMap();
Map map2 = new HashMap();
map1.put(3, 3);
map2.put(5, 5);
coll.add(map1);
coll.add(map2);
System.out.println("未修改的map1的hashCode:"+map1.hashCode());
System.out.println("未移除map1之后的coll的长度:"+coll.size());
System.out.println(coll.toString());
map1.put(3,7);
coll.remove(map1);
System.out.println("修改后的map1的hashCode:"+map1.hashCode());
System.out.println("移除map1之后的coll的长度:"+coll.size());
System.out.println(coll.toString());
}

对于已经加入HashSet的对象,如果修改参与计算HashCode的属性的信息,会导致删除该HashSet中的该对象无效,从而导致内存泄漏。

java中对内存泄漏的应对机制:

java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动 被垃圾回收器从内存中清除掉。由于 Java 使用有向图的方式进行垃圾回收管理,可以消除 引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么 GC 也是 可以回收它们的,例如下面的代码可以看到这种情况的内存回收:

import java.io.IOException;

publicclass GarbageTest {
public static voidmain(String[] args)throws IOException {
try {
gcTest();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("hasexited gcTest!");
System.in.read();
System.in.read();
System.out.println("out begingc!");
for(int i=0;i<100;i++){
System.gc();
System.in.read();
System.in.read();
}
}
private static voidgcTest()throws IOException {
System.in.read();
System.in.read();
Person p1 = new Person();
System.in.read();
System.in.read();
Person p2 = new Person();
p1.setMate(p2);
p2.setMate(p1);
System.out.println("beforeexit gctest!");
System.in.read();
System.in.read();
System.gc();
System.out.println("exitgctest!");
}
private static classPerson{
byte[] data =new byte[20000000];
Person mate = null;
public void setMate(Personother){
mate = other;
}
}
}

避免内存泄漏的方法:

  1. 程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。
  2. 尽量少用静态变量。
  3. 避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。
  4. 尽量运用对象池技术以提高系统性能。
  5. 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。
  6. 尽早释放无用对象的引用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: