Examples of common java memory leak

JAVA 中的内存泄露

    Java中的内存泄露,广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露。

    Java中的内存泄露与C++中的表现有所不同。

    在C++中,所有被分配了内存的对象,不再使用后,都必须程序员手动的释放他们。所以,每个类,都会含有一个析构函数,作用就是完成清理工作,如果我们忘记了某些对象的释放,就会造成内存泄露。

    但是在Java中,我们不用(也没办法)自己释放内存,无用的对象由GC自动清理,这也极大的简化了我们的编程工作。但,实际有时候一些不再会被使用的对象,在GC看来不能被释放,就会造成内存泄露。

    我们知道,对象都是有生命周期的,有的长,有的短,如果长生命周期的对象持有短生命周期的引用,就很可能会出现内存泄露。我们举一个简单的例子:

public  class the Simple { 
    Object Object ;
     public  void the method1 () {
         Object = new new Object ();
         // ... other code 
    } 
}

  object instance here, in fact we expect it only acts on the method1 () method, and the rest will not use it, however, when the method1 () method execution is complete, the allocated memory object objects will not immediately be considered object can be released, and will only be released after the Simple Object class created is released, strictly speaking, this is a memory leak. The solution is the object as a local variable methods method1 () in. Of course, if you have to write so, you can change this:

public  class the Simple { 
    Object Object; 
    public  void the method1 () { 
        Object = new new Object ();
         // ... other code 
        Object = null ; 
    } 
}

   这样,之前“new Object()”分配的内存,就可以被GC回收。

    到这里,Java的内存泄露应该都比较清楚了。下面再进一步说明:

  •     在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值),这是针对c++等语言的,Java中的GC会帮我们处理这种情况,所以我们无需关心。
  •     在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用),这是所有语言都有可能会出现的内存泄漏方式。编程时如果不小心,我们很容易发生这种情况,如果不太严重,可能就只是短暂的内存泄露。

一些容易发生内存泄露的例子和解决方法

    像上面例子中的情况很容易发生,也是我们最容易忽略并引发内存泄露的情况,解决的原则就是尽量减小对象的作用域(比如android studio中,上面的代码就会发出警告,并给出的建议是将类的成员变量改写为方法内的局部变量)以及手动设置null值。

    至于作用域,需要在我们编写代码时多注意;null值的手动设置,我们可以看一下Java容器LinkedList源码(可参考:Java之LinkedList源码解读(JDK 1.8))的删除指定节点的内部方法:

// delete the specified node and returns the deleted element values 
E The unlink (the Node <E> X) {
     // get the current value before and after the node 
    Final E = Element x.item;
     Final the Node <E> = Next x.next;
     Final the node <E> PREV = x.prev;
     IF (PREV == null ) { 
        first = Next; // if the previous node is empty (such as the current node as the ingress node), the node becomes a new first node 
    } the else { 
        PREV .next = the next; // If the previous node is not empty, then he has directed the current to the next node 
        x.prev = null ; 
    } 
    IF (the next == null  ) {
        Last = PREV; // If the node is empty (such as the current node is tail node), this becomes a new node before the tail node 
    } the else { 
        next.prev = PREV; // If the node is not empty, the a forward current node pointing to a front node 
        x.next = null ; 
    } 
    x.item = null ; 
    size - ; 
    ModCount ++ ;
     return Element; 
}

容器使用时的内存泄露

In many articles you may see a memory leak following example:

Vector v = new Vector();
for (int i = 1; i<100; i++){
    Object o = new Object();
    v.add(o);
    o = null;
}

    Here memory leak means that after the completion of vector operations, following the implementation of vector-independent code, if it does GC operation, this series of object is not recycled, but here's a memory leak may be short-lived , because the entire execution completion method () method, or objects that can be recovered. To work around here is very simple, you can manually assigned to null:

Vector v = new Vector();
for (int i = 1; i<100; i++){
    Object o = new Object();
    v.add(o);
    o = null;
}
v = null;

Above Vector outdated, but just use the old example to make an introduction memory leaks. We are prone to memory leaks when using the container, as the above example, but the example above, when the container is a local variable within a method, a memory leak may impact is not great (but we should avoid), but if the vessel as a member variable of a class, or even a static (static) member variables, we should pay more attention to the memory leak.

 

    Singleton cause memory leaks

 

    Singleton, many times we can put its life cycle and throughout the life of the program seen as similar, it is the object of a long life cycle. If the object holds references to other objects, it is also very prone to memory leaks.

 For example: following this common wording, it passed into a Context

import android.content.Context;
 
public class Utils {
    private Context mContext;
    private static Utils utils;
 
    private Utils(Context mContext) {
        this.mContext = mContext;
    }
 
    public static Utils getInstance(Context mContext) {
        if (utils == null) {
            synchronized (Utils.class) {
                if (utils == null) {
                    utils = new Utils(mContext);
                }
            }
        }
        return utils;
    }
}

When we use:

public class MainActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Utils.getInstance(this);
    }
}

We create a Activity in the SingleInstance, and transmits this to the Activity class instance of the object, causing the singleton object holds a reference to the corresponding Activity. When we Activity quit because SingleInstance there, it's not the end of the life cycle, so SingleInstance still holds a reference to the Activity instance, due to the Activity have been cited, leading to instances Activity can not be recycled, will long exist Activity memory.

Solution: Use a weak reference.

Guess you like

Origin www.cnblogs.com/zheng123/p/11356851.html