简书链接:SoftReferenceWeakReference区别避免混淆软引用和弱引用的不同从源码注释入手以及手写测试避免记错混淆使用谐音记忆法
文章字数:1831,阅读全文大约需要7分钟
我的app很头疼,
有时候很容易记混淆,搞不懂哪个是内存不足才会回收,哪个随时可能被回收 哪个调用gc之后一定会回收,哪个是安卓推荐使用的..

那么先从安卓的源码开始,打开源码发现有一段注释证明软引用不推荐使用,

SoftReference

1
2


  • Soft reference objects, which are cleared at the discretion of the garbage
  • collector in response to memory demand.
  • Suppose that the garbage collector determines at a certain point in time

  • that an object is softly
  • reachable. At that time it may choose to clear atomically all soft
  • references to that object and all soft references to any other
  • softly-reachable objects from which that object is reachable through a chain
  • of strong references. At the same time or at some later time it will
  • enqueue those newly-cleared soft references that are registered with
  • reference queues.
  • All soft references to softly-reachable objects are guaranteed to have

  • been cleared before the virtual machine throws an
    OutOfMemoryError . Otherwise no constraints are placed upon the
  • time at which a soft reference will be cleared or the order in which a set
  • of such references to different objects will be cleared. Virtual machine
  • implementations are, however, encouraged to bias against clearing
  • recently-created or recently-used soft references.
  • Avoid Soft References for Caching

  • In practice, soft references are inefficient for caching. The runtime doesn’t
  • have enough information on which references to clear and which to keep. Most
  • fatally, it doesn’t know what to do when given the choice between clearing a
  • soft reference and growing the heap.
  • The lack of information on the value to your application of each reference

  • limits the usefulness of soft references. References that are cleared too
  • early cause unnecessary work; those that are cleared too late waste memory.
  • Most applications should use an {@code android.util.LruCache} instead of

  • soft references. LruCache has an effective eviction policy and lets the user
  • tune how much memory is allotted.
  • @author Mark Reinhold
  • @since 1.2

*/

1
2
3
4
5
6
7
8
9
从上面有几个关键英文单词
```Avoid Soft References for Caching```
```Most applications should use an {@code android.util.LruCache} ```
避免使用, 大部分应用应该使用```LruCache``` 这里说的很清楚,不是绝对,一定,不是必须使用LruCache, fragment的存储缓存是无法知道大小的,LruCache 我是不知道怎么整,翻阅了百度也找不到任何答案,测量obj大小的方法 也被谷歌删除了.fragment的存储到底用哪个好呢?

避免使用缓存缓存的软引用
*实际上,软引用对于缓存是无效的。运行时没有足够的信息,说明哪些要明确,哪些要保留。最
*致命的

All soft references to softly-reachable objects are guaranteed to have

  • been cleared before the virtual machine throws an
  • OutOfMemoryError. O
    1
    2
    3
    4
    5
    6
    ```guaranteed ``` 保证
    虚拟机保证在内存不足之前清理所有Soft references,我英语不好,应该是说内存不足的时候才会清除?还是说内存不足的时候一定会清除,但是不足的时候清除不清除呢?

    # **WeakReference**

    注释:

/**

  • Weak reference objects, which do not prevent their referents from being
  • made finalizable, finalized, and then reclaimed. Weak references are most
  • often used to implement canonicalizing mappings.
  • Suppose that the garbage collector determines at a certain point in time

  • that an object is weakly reachable. At that time it will atomically clear all weak references to
  • that object and all weak references to any other weakly-reachable objects
  • from which that object is reachable through a chain of strong and soft
  • references. At the same time it will declare all of the formerly
  • weakly-reachable objects to be finalizable. At the same time or at some
  • later time it will enqueue those newly-cleared weak references that are
  • registered with reference queues.

*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14








软引用验证,只有内存不足才会回收 如果回收了还是内存不足就鸡鸡了,这很适合用在fragment的缓存,因为内存还足够没必要回收.

下面是我测试SoftReference的程序,用eclipse测试最好不过了,调整最大内存为2M,初始化内存也为2M

### 改配置感受 紧

Launch configurations for ‘TestReference.java’ ->Argments选项卡 Vm argments里面填写参数-Xmx2m -xms2m

1
2
3
4
5

![image.png](https://upload-images.jianshu.io/upload_images/2815884-3e5d89fa436d49cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/500)

### 测试软引用源代码

/**
 *Launch configurations for 'TestReference.java'  ->Argments选项卡  Vm argments里面填写参数-Xmx2m -xms2m   
 * @param args
 */
public static void main(String[] args) {
    Object referent = new Object();
    java.util.List<String[]> list = new ArrayList<>();
    SoftReference<Object> softRerference = new SoftReference<Object>(referent);

    assertNotNull(softRerference.get());

    referent = null;

    int count = 0;

    while (softRerference.get()!=null) {
        System.out.println("obj!=null count:" + count);
        count++;
        String[] current=new String[1000];
        System.out.println("isempty:"+(softRerference.get()==null));
        list.add(current);
        for (int i = 0; i < current.length; i++) {
            
            current[i]=i+"";
        }
        
    
                    if(count%1000==0){
                    }
    }
    
    System.out.println("obj is recycle");

    /**
     * soft references 只有在 jvm OutOfMemory 之前才会被回收, 如果回收后发现还是内存不足,那么蛋蛋了
     * Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.Arrays.copyOfRange(Arrays.java:3664)
at java.lang.String.<init>(String.java:207)
at java.lang.StringBuilder.toString(StringBuilder.java:407)
at TestReference.main(TestReference.java:29)
     * 
     */
    
}
1
2
3
4

### 弱引用测试


static class MyObj {
    public MyObj(int no) {
        this.no = no;
    }

    public String[] getCurrent() {
        return current;
    }

    public void setCurrent(String[] current) {
        this.current = current;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    String[] current = new String[1000];
    int no;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("from:"+no+" :我被回收了我是hasCode:" + hashCode());
        super.finalize();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
```
/**
*Launch configurations for 'TestReference.java' ->Argments选项卡 Vm argments里面填写参数-Xmx2m -xms2m
* @param args
*/
public static void main(String[] args) {
Object referent = new Object();
java.util.List<WeakReference<MyObj>> list = new ArrayList<>();
int loopindex = 0;
System.err.println("=================================弱引用测试=================================");
while(loopindex<200){

String[] current=new String[500];
for (int i = 0; i < current.length; i++) {

current[i]=i+"";
}
MyObj obj=new MyObj(loopindex);
obj.setCurrent(current);
list.add(new WeakReference<TestReference.MyObj>(obj));
if(loopindex%5==0&&loopindex>0){
System.out.println("start================"+loopindex+"================================");
System.out.println("即将调用调用主动gc,刚刚放进去的对象index:"+loopindex+"还在否:"+list.get(loopindex).get());
System.gc();
System.out.println("主动调用gc");
System.out.println("调用之后刚刚放进去的对象index:"+loopindex+"还在否:"+list.get(loopindex).get());
System.out.println("调用之后第一个还在否:"+list.get(0).get());
System.out.println("end================"+loopindex+"================================");
}
loopindex++;
}




/**

*
*/

}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
=================================弱引用测试=================================
start================5================================
即将调用调用主动gc,刚刚放进去的对象index:5还在否:TestReference$MyObj@6d06d69c
主动调用gc
调用之后刚刚放进去的对象index:5还在否:TestReference$MyObj@6d06d69c
调用之后第一个还在否:null
end================5================================
from:2 :我被回收了我是hasCode:1113044619
from:3 :我被回收了我是hasCode:1284526257
from:4 :我被回收了我是hasCode:1219485179
from:1 :我被回收了我是hasCode:229464714
from:0 :我被回收了我是hasCode:1915835994
start================10================================
即将调用调用主动gc,刚刚放进去的对象index:10还在否:TestReference$MyObj@7852e922
主动调用gc
调用之后刚刚放进去的对象index:10还在否:TestReference$MyObj@7852e922
调用之后第一个还在否:null
end================10================================
from:9 :我被回收了我是hasCode:1022006645
from:8 :我被回收了我是hasCode:178046742
from:7 :我被回收了我是hasCode:1837278661
from:6 :我被回收了我是hasCode:368688553
from:5 :我被回收了我是hasCode:1829164700
start================15================================
即将调用调用主动gc,刚刚放进去的对象index:15还在否:TestReference$MyObj@4e25154f
主动调用gc
from:10 :我被回收了我是hasCode:2018699554
调用之后刚刚放进去的对象index:15还在否:TestReference$MyObj@4e25154f
from:14 :我被回收了我是hasCode:2102444894
调用之后第一个还在否:null
from:13 :我被回收了我是hasCode:295178133
from:12 :我被回收了我是hasCode:1774992622
from:11 :我被回收了我是hasCode:822136971
end================15================================
start================20================================

测试调节初始化数组大小为500 或者1000 如果是1千,我们发现即使没有调用System.gc()它已经开始进行回收了,也就是稍微吃紧就会回收了,而改成500之后 第一次loop,没有回收等到调用gc执行完毕start-end逻辑后, 3 ,4,2,1,0都一个一个被回收了,从这里的消息也可以看出,回收虽然不会超大概率回收刚刚放进去的,但是也不会百分百先回收第一个,或者也许是日志打印和本地native消息不同步导致的??

看上去好像差不多,意思是在不定期检测 弱引用对象,那些不可达的进行清除.
但是没有说内存不足``oom```之前弱引用对象就一定已经被清除了。。

WeakHashMap 对于集合来说,用WeakHashMap也许更方便

软引用 手动调用System.gc回收的时候软引用不一定会回收, 但是弱引用一定会被回收,所以你是打算用软引用还是用弱引用呢?

为了加深印象避免混淆,我打算给他们取一个名字 ,软足弱鸡g ,也就是软引用是内存不足才会瘦 ,弱引用 gc马上会瘦
参考链接
http://san-yun.iteye.com/blog/1683558
https://baijiahao.baidu.com/s?id=1578867464445861486&wfr=spider&for=pc
http://www.cnblogs.com/skywang12345/p/3154474.html
测试案例参考
http://wiseideal.iteye.com/blog/1469295