java内存泄漏

参考YourAaron的博客,网址:https://blog.csdn.net/weter_drop/article/details/89387564

参考:https://www.jianshu.com/p/420bacba1b12

一、长生命周期的对象持有短生命周期的引用

解决内存泄漏的一个方法,就是尽量降低变量的作用域,以及时时把对象复制为可清理对象(null)

public class Simple   {
       Object object;
       void method () {
              object = new Object();
        }
}

严格意义上就是一种内存泄漏,因为object不在被使用,但他不会立即被回收,而是等到Simple对象被释放的时候。

这样写,可以。

public class Simple   {
       Object object;
       void method () {
              Object object = new Object();
              //使用Object
              object = null;
        }
}

把Object定义为局部变量,并在最后赋值为null

同时,ArrayList的pop方法:

public E pop(){
    if(size == 0)
        return null;
    else{
          E e = (E) elementData[--size];
          elementData[size] = null;
          return e;
  }
}

 

容器使用时的内存泄漏

      Vector vector = new Vector();
      for (int i = 1; i<100; i++)
    {
          Object object = new Object();
          vector.add(object);
          object = null;
      }
      //...对vector的操作
      //...与vector无关的其他操作
}

这里其实只是会造成短暂的内存泄漏,在method方法结束后还是会把回收的,更好的写法是:

      Vector vector = new Vector();
      for (int i = 1; i<100; i++)
    {
          Object object = new Object();
          vector.add(object);
          object = null;
      }
      //...对vector的操作
      vector = null;
      //...与vector无关的其他操作
}

 

在各种IO或者数据库连接中,都需要在最后通过close()方法释放对象,这里也是长对象引用短对象是造成的内存泄漏

SessionFactory factory = new SessionFactory();
try {
Session session = factory.connect();
} finally{
      session.close();
}

这里必须用close关闭连接,因为SessionFactory是长对象,session是短对象。

 

 

可以看到WeakHashMap的key是弱引用,ThreadLocal的key也是用的弱引用,但是WeakHashMap在被GC回收时value也会被回收了,而ThreadLocal则不会,ThreadLocal必须显示的调用一下remove方法才能将value的值给清空。
在两个的源码中可以看到,ThreadLocal里面并没有一个接受对象被GC回收后通知的ReferenceQueue,所以就算key被回收了,value也是存在的,并不会和WeakHashMap一样,在key被清空后,可以使用ReferenceQueue这个队列接受被GC的通知,然后把value也自己给清空。
 

 

-Xmn10M 年轻带10M -XX:SurvivorRatio=8,此为Eden区域和Survivor区域(From幸存区或To幸存区)的比例,默认为8,也就是说Eden占新生代的8/10,From幸存区和To幸存区各占新生代的1/10。

 

当GC增加时,或者内存占用的不断增加,序性能的降低就会表现出来,严重时可导致内存泄漏

当进行大量的pop操作时,由于引用未进行置空,gc是不会释放的。

从上图中看以看出,如果栈先增长,在收缩,那么从栈中弹出的对象将不会被当作垃圾回收,即使程序不再使用栈中的这些队象,他们也不会回收,因为栈中仍然保存这对象的引用,俗称过期引用,这个内存泄露很隐蔽。

解决方法:

public Object pop() {
    if (size == 0)
    throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null;
    return result;
}

原始为:


import java.util.Arrays;

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    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)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

 

 

2.缓存泄漏

内存泄漏的另一个常见来源是缓存,一旦你把对象引用放入到缓存中,他就很容易遗忘,对于这个问题,可以使用WeakHashMap代表缓存,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值

 

WeakHashMap就是一个HashMap,只不过它的key继承了WeakReference表示key是一个弱引用,在GC时就会被回收。

 

其中WeakHashMap

输出为:

String引用ref1,ref2,ref3,ref4 消失
WeakHashMap GC之前
obejct2=chaheObject2
obejct1=chaheObject1
WeakHashMap GC之后
HashMap GC之前
obejct4=chaheObject4
obejct3=chaheObject3
HashMap GC之后
obejct4=chaheObject4
obejct3=chaheObject3
 


import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;

public class Test3 {
    static Map wMap = new WeakHashMap();
    static Map map = new HashMap();
    public static void main(String[] args) {
        init();
        testWeakHashMap();
        testHashMap();
    }



    public static void init(){
        String ref1= new String("obejct1");
        String ref2 = new String("obejct2");
        String ref3 = new String ("obejct3");
        String ref4 = new String ("obejct4");
        wMap.put(ref1, "chaheObject1");
        wMap.put(ref2, "chaheObject2");
        map.put(ref3, "chaheObject3");
        map.put(ref4, "chaheObject4");
        System.out.println("String引用ref1,ref2,ref3,ref4 消失");

    }
    public static void testWeakHashMap(){

        System.out.println("WeakHashMap GC之前");
        for (Object o : wMap.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("WeakHashMap GC之后");
        for (Object o : wMap.entrySet()) {
            System.out.println(o);
        }
    }
    public static void testHashMap(){
        System.out.println("HashMap GC之前");
        for (Object o : map.entrySet()) {
            System.out.println(o);
        }
        try {
            System.gc();
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("HashMap GC之后");
        for (Object o : map.entrySet()) {
            System.out.println(o);
        }
    }

}

 

 

 

 

 

 

 

你可能感兴趣的:(jvm)