Java内存泄露的理解与解决

news/2024/7/20 14:39:29 标签: 数据结构与算法, 内存管理, java

Java内存管理机制

在C++语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期。从申请分配、到使用、再到最后的释放。这样的过程非常灵活,但是却十分繁琐,程序员很容易由于疏忽而忘记释放内存,从而导致内存的泄露。Java语言对内存管理做了自己的优化,这就是垃圾回收机制。Java的几乎所有内存对象都是在堆内存上分配(基本数据类型除外),然后由GC(garbage collection)负责自动回收不再使用的内存。

上面是Java内存管理机制的基本情况。但是如果仅仅理解到这里,我们在实际的项目开发中仍然会遇到内存泄漏的问题。也许有人表示怀疑,既然Java的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢?这个问题,我们需要知道GC在什么时候回收内存对象,什么样的内存对象会被GC认为是“不再使用”的。

Java中对内存对象的访问,使用的是引用的方式。在Java代码中我们维护一个内存对象的引用变量,通过这个引用变量的值,我们可以访问到对应的内存地址中的内存对象空间。在Java程序中,这个引用变量本身既可以存放堆内存中,又可以放在代码栈的内存中(与基本数据类型相同)。GC线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的。如果GC线程通过这种方式,无法跟踪到某一块堆内存,那么GC就认为这块内存将不再使用了(因为代码中已经无法访问这块内存了)。

java.net/images/blogjava_net/zh-weir/java_memory_manage/java_memory.png" alt="" width="554" height="192" border="0" />

通过这种有向图的内存管理方式,当一个内存对象失去了所有的引用之后,GC就可以将其回收。反过来说,如果这个对象还存在引用,那么它将不会被GC回收,哪怕是Java虚拟机抛出OutOfMemoryError。

Java内存泄露

一般来说内存泄漏有两种情况。一种情况如在C/C++语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解决。所以,Java中的内存泄漏,主要指的是第二种情况。

可能光说概念太抽象了,大家可以看一下这样的例子:

 

1 Vector v=new Vector(10);
2 for (int i=1;i<100; i++){
3 Object o=new Object();
4 v.add(o);
5 o=null;
6 }

 在这个例子中,代码栈中存在Vector对象的引用v和Object对象的引用o。在For循环中,我们不断的生成新的对象,然后将其添加到Vector对象中,之后将o引用置空。问题是当o引用被置空后,如果发生GC,我们创建的Object对象是否能够被GC回收呢?答案是否定的。因为,GC在跟踪代码栈中的引用时,会发现v引用,而继续往下跟踪,就会发现v引用指向的内存空间中又存在指向Object对象的引用。也就是说尽管o引用已经被置空,但是Object对象仍然存在其他的引用,是可以被访问到的,所以GC无法将其释放掉。如果在此循环之后,Object对象对程序已经没有任何作用,那么我们就认为此Java程序发生了内存泄漏。

尽管对于C/C++中的内存泄露情况来说,Java内存泄露导致的破坏性小,除了少数情况会出现程序崩溃的情况外,大多数情况下程序仍然能正常运行。但是,在移动设备对于内存和CPU都有较严格的限制的情况下,Java的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机

在不涉及复杂数据结构的一般情况下,Java的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。我们有时也将其称为“对象游离”。

例如:

 1 public class FileSearch{
2
3     private byte[] content;
4     private File mFile;
5
6     public FileSearch(File file){
7         mFile = file;
8     }
9
10     public boolean hasString(String str){
11         int size = getFileSize(mFile);
12         content = new byte[size];
13         loadFile(mFile, content);
14
15         String s = new String(content);
16         return s.contains(str);
17     }
18 }

在这段代码中,FileSearch类中有一个函数hasString,用来判断文档中是否含有指定的字符串。流程是先将mFile加载到内存中,然后进行判断。但是,这里的问题是,将content声明为了实例变量,而不是本地变量。于是,在此函数返回之后,内存中仍然存在整个文件的数据。而很明显,这些数据我们后续是不再需要的,这就造成了内存的无故浪费。

要避免这种情况下的内存泄露,要求我们以C/C++的内存管理思维来管理自己分配的内存。第一,是在声明对象引用之前,明确内存对象的有效作用域。在一个函数内有效的内存对象,应该声明为local变量,与类实例生命周期相同的要声明为实例变量……以此类推。第二,在内存对象不再需要时,记得手动将其引用置空。

复杂数据结构中的内存泄露问题

在实际的项目中,我们经常用到一些较为复杂的数据结构用于缓存程序运行过程中需要的数据信息。有时,由于数据结构过于复杂,或者我们存在一些特殊的需求(例如,在内存允许的情况下,尽可能多的缓存信息来提高程序的运行速度等情况),我们很难对数据结构中数据的生命周期作出明确的界定。这个时候,我们可以使用Java中一种特殊的机制来达到防止内存泄露的目的。

之前我们介绍过,Java的GC机制是建立在跟踪内存的引用机制上的。而在此之前,我们所使用的引用都只是定义一个“Object o;”这样形式的。事实上,这只是Java引用机制中的一种默认情况,除此之外,还有其他的一些引用方式。通过使用这些特殊的引用机制,配合GC机制,就可以达到一些我们需要的效果。

JAVA中的几种引用方式

Java中有几种不同的引用方式,它们分别是:强引用、软引用、弱引用和虚引用。下面,我们首先详细地了解下这几种引用方式的意义。
强引用

在此之前我们介绍的内容中所使用的引用都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

软引用(SoftReference)

SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。SoftReference 的原理是:在保持对对象的引用时保证在 JVM 报告内存不足情况之前将清除所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法 以及垃圾收集器运行时可用的内存数量。

弱引用(WeakReference)

WeakReference 类的一个典型用途就是规范化映射(canonicalized mapping)。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放 WeakReference 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。

虚引用(PhantomReference)

PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时,PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。Reference与ReferenceQueue的配合使用。

GC、REFERENCE与REFERENCEQUEUE的交互

A、 GC无法删除存在强引用的对象的内存。

B、 GC发现一个只有软引用的对象内存,那么:

① SoftReference对象的referent 域被设置为null,从而使该对象不再引用heap对象。

② SoftReference引用过的heap对象被声明为finalizable。

③ 当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放,SoftReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。

C、 GC发现一个只有弱引用的对象内存,那么:

① WeakReference对象的referent域被设置为null,从而使该对象不再引用heap对象。

② WeakReference引用过的heap对象被声明为finalizable。

③ 当heap对象的finalize()方法被运行而且该对象占用的内存被释放时,WeakReference对象就被添加到它的ReferenceQueue(如果后者存在的话)。

D、 GC发现一个只有虚引用的对象内存,那么:

① PhantomReference引用过的heap对象被声明为finalizable。

② PhantomReference在堆对象被释放之前就被添加到它的ReferenceQueue。

值得注意的地方有以下几点:

1、GC在一般情况下不会发现软引用的内存对象,只有在内存明显不足的时候才会发现并释放软引用对象的内存。

2、GC对弱引用的发现和释放也不是立即的,有时需要重复几次GC,才会发现并释放弱引用的内存对象。
3、软引用和弱引用在添加到ReferenceQueue的时候,其指向真实内存的引用已经被置为空了,相关的内存也已经被释放掉了。而虚引用在添加到ReferenceQueue的时候,内存还没有释放,仍然可以对其进行访问。

    代码示例

通过以上的介绍,相信您对Java的引用机制以及几种引用方式的异同已经有了一定了解。光是概念,可能过于抽象,下面我们通过一个例子来演示如何在代码中使用Reference机制。

 

1     String str = new String("hello"); //①
2     ReferenceQueue<String> rq = new ReferenceQueue<String>(); //②
3     WeakReference<String> wf = new WeakReference<String>(str, rq); //③
4     str=null; //④取消"hello"对象的强引用
5     String str1=wf.get(); //⑤假如"hello"对象没有被回收,str1引用"hello"对象
6     //假如"hello"对象没有被回收,rq.poll()返回null
7     Reference<? extends String> ref=rq.poll(); //⑥

 

 

在以上代码中,注意⑤⑥两处地方。假如“hello”对象没有被回收wf.get()将返回“hello”字符串对象,rq.poll()返回null;而加入“hello”对象已经被回收了,那么wf.get()返回null,rq.poll()返回Reference对象,但是此Reference对象中已经没有str对象的引用了(PhantomReference则与WeakReference、SoftReference不同)。

    引用机制与复杂数据结构的联合应用

了解了GC机制、引用机制,并配合上ReferenceQueue,我们就可以实现一些防止内存溢出的复杂数据类型。

例如,SoftReference具有构建Cache系统的特质,因此我们可以结合哈希表实现一个简单的缓存系统。这样既能保证能够尽可能多的缓存信息,又可以保证Java虚拟机不会因为内存泄露而抛出OutOfMemoryError。这种缓存机制特别适合于内存对象生命周期长,且生成内存对象的耗时比较长的情况,例如缓存列表封面图片等。对于一些生命周期较长,但是生成内存对象开销不大的情况,使用WeakReference能够达到更好的内存管理的效果。

附SoftHashmap的源码一份,相信看过之后,大家会对Reference机制的应用有更深入的理解。

 

  1 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />package com.***.widget;
2 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />
3 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />//: SoftHashMap.java
4 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />import java.util.*;
5 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />import java.lang.ref.*;
6 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />
7 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />import android.util.Log;
8 java.net/Images/OutliningIndicators/None.gif" alt="" align="top" />
9 java.net/Images/OutliningIndicators/ExpandedBlockStart.gif" alt="" align="top" />public class SoftHashMap extends AbstractMap {
10 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** The internal HashMap that will hold the SoftReference. */
11 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />  private final Map hash = new HashMap();
12 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** The number of "hard" references to hold internally. */
13 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />  private final int HARD_SIZE;
14 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** The FIFO list of hard references, order of last access. */
15 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />  private final LinkedList hardCache = new LinkedList();
16 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** Reference queue for cleared SoftReference objects. */
17 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />  private ReferenceQueue queue = new ReferenceQueue();
18 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />
19 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />  //Strong Reference number
20 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public SoftHashMap() { this(100); }
21 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public SoftHashMap(int hardSize) { HARD_SIZE = hardSize; }
22 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />
23 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />
24 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public Object get(Object key) {
25 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    Object result = null;
26 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    // We get the SoftReference represented by that key
27 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    SoftReference soft_ref = (SoftReference)hash.get(key);
28 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />    if (soft_ref != null) {
29 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      // From the SoftReference we get the value, which can be
30 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      // null if it was not in the map, or it was removed in
31 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      // the processQueue() method defined below
32 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      result = soft_ref.get();
33 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />      if (result == null) {
34 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // If the value has been garbage collected, remove the
35 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // entry from the HashMap.
36 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        hash.remove(key);
37 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />      } else {
38 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // We now add this object to the beginning of the hard
39 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // reference queue.  One reference can occur more than
40 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // once, because lookups of the FIFO queue are slow, so
41 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // we don't want to search through it each time to remove
42 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        // duplicates.
43 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />          //keep recent use object in memory
44 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />        hardCache.addFirst(result);
45 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />        if (hardCache.size() > HARD_SIZE) {
46 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />          // Remove the last entry if list longer than HARD_SIZE
47 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />          hardCache.removeLast();
48 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />        }
49 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />      }
50 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />    }
51 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    return result;
52 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
53 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />
54 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** We define our own subclass of SoftReference which contains
55 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />   not only the value but also the key to make it easier to find
56 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />   the entry in the HashMap after it's been garbage collected. */
57 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  private static class SoftValue extends SoftReference {
58 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    private final Object key; // always make data member final
59 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />    /** Did you know that an outer class can access private data
60 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />     members and methods of an inner class?  I didn't know that!
61 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />     I thought it was only the inner class who could access the
62 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />     outer class's private information.  An outer class can also
63 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />     access private members of an inner class inside its inner
64 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />     class. */
65 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />    private SoftValue(Object k, Object key, ReferenceQueue q) {
66 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      super(k, q);
67 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      this.key = key;
68 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />    }
69 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
70 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />
71 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** Here we go through the ReferenceQueue and remove garbage
72 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />   collected SoftValue objects from the HashMap by looking them
73 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />   up using the SoftValue.key data member. */
74 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public void processQueue() {
75 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    SoftValue sv;
76 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />    while ((sv = (SoftValue)queue.poll()) != null) {
77 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />        if(sv.get()== null){
78 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />            Log.e("processQueue", "null");
79 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />        }else{
80 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />            Log.e("processQueue", "Not null");
81 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />        }
82 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      hash.remove(sv.key); // we can access private data!
83 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />      Log.e("SoftHashMap", "release " + sv.key);
84 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />    }
85 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
86 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  /** Here we put the key, value pair into the HashMap using
87 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />   a SoftValue object. */
88 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public Object put(Object key, Object value) {
89 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    processQueue(); // throw out garbage collected values first
90 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    Log.e("SoftHashMap", "put into " + key);
91 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    return hash.put(key, new SoftValue(value, key, queue));
92 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
93 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public Object remove(Object key) {
94 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    processQueue(); // throw out garbage collected values first
95 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    return hash.remove(key);
96 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
97 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public void clear() {
98 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    hardCache.clear();
99 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    processQueue(); // throw out garbage collected values
100 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    hash.clear();
101 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
102 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public int size() {
103 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    processQueue(); // throw out garbage collected values first
104 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    return hash.size();
105 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
106 java.net/Images/OutliningIndicators/ExpandedSubBlockStart.gif" alt="" align="top" />  public Set entrySet() {
107 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    // no, no, you may NOT do that!!! GRRR
108 java.net/Images/OutliningIndicators/InBlock.gif" alt="" align="top" />    throw new UnsupportedOperationException();
109 java.net/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" alt="" align="top" />  }
110 java.net/Images/OutliningIndicators/ExpandedBlockEnd.gif" alt="" align="top" />}

性能变差,严重的也会引起抛出OutOfMemoryError,导致程序崩溃。

一般情况下内存泄漏的避免

 

 

转载于:https://www.cnblogs.com/luxiaorui/p/3930974.html


http://www.niftyadmin.cn/n/670077.html

相关文章

JAVA基础mysql和jdbc_JDBC编程和MySQL数据库

{getUnitName}{getLessonName}敬请期待免费{getTaskName}剩余观看时长&#xff1a;{watchLimitRemaining}回放{activityStartTimeStr}正在直播中直播结束{activityLength}免费{getTaskName}敬请期待{"id": "203","isDefault": "1",&qu…

职场不同学生时代

1.社会不在乎你的尊严,尊严要靠你履行自己的工作职责来争取 2 没人在乎你的意见,你可以发表,但大多数时间是废话 3 不要以为只有你有压力,你的主管也许压力比你更大, 4 不要把对你好的人当好人,也不要把对你恶的人当恶人 5 正常的锻炼当锻炼,非常的锻炼当磨练 6 受了…

使用DCOM读取excel文件时,如果文件中存在不可用的连接,总是弹窗提示框让编辑连接。如何消除提示框呢?...

看到很多地方说&#xff0c;在服务器上&#xff0c;设置excel选项&#xff0c;但是这种设置只针对特定的excel文件 最终解决办法&#xff1a; Workbooks.Open(fileName, 0, true, TypeM, TypeM, TypeM, true, TypeM, TypeM, true, TypeM, TypeM, TypeM, TypeM, TypeM); //注意第…

python数据表达式_Python数据类型和表达式

Python数据类型和表达式标识符(Identifier)‣由程序员定义的名字&#xff1b;‣ 允许采用大写字母、小写字母、数字、下划线(_)和汉字等字 符&#xff0c;但标识符的首字符不能是数字&#xff0c;中间不能出现空格&#xff1b;‣大小写敏感&#xff1b;‣ 不能与保留字相同&…

基于Andoird 4.2.2的Account Manager源代码分析学习:AccountManagerService系统服务的添加...

从启动说起 Android系统加载时&#xff0c;首先启动init进程&#xff0c;该进程会启动Zygote进程。Zygote进程执行/system/bin/app_process程序。app_process程序在执行中&#xff0c;通过AppRuntime::start()函数来创建虚拟机实例&#xff0c;并注册JNI方法。 int main(int ar…

iOS中的单元测试(一)

转载自http://www.infoq.com/cn/articles/ios-unit-test-1 导读&#xff1a;本文不讨论单元测试是什么&#xff0c;或者它之于一个工程的利弊&#xff0c;我认为单元测试是一个开发者保证产出代码质量的有效工具。本文从使用者的角度对比当下比较流行的两款单元测试框架&#x…

java带时区时间格式_Java中日期格式化SimpleDateFormat类包含时区的处理方法

1.前言需要把格式为“2017-02-23T08:04:0201:00”转化成”23-02-2017-T15:04:02“格式(中国时区为08:00所以是15点)&#xff0c;通过网上查找答案&#xff0c;发现没有我需要的答案&#xff0c;最后我直接查看了java.text.SimpleDateFormat类的介绍&#xff0c;问题解决了。2.格…