在Java中,雖然不需要程序員手動去管理對象的生命周期,但是如果希望某些對象具備一定的生命周期的話(比如內存不足時JVM就會自動回收某些對象從而避免OutOfMemory的錯誤)就需要用到軟引用和弱引用了。
從Java SE2開始,就提供了四種類型的引用:強引用、軟引用、弱引用和虛引用。Java中提供這四種引用類型主要有兩個目的:第一是可以讓程序員通過代碼的方式決定某些對象的生命周期;第二是有利於JVM進行垃圾回收。下面來闡述一下這四種類型引用的概念:
引用分為四個,從高到低的級別以此為強引用-軟引用-弱引用-虛引用.
-
引用類型
類別 回收機制 用途 生存時間 強引用 從不回收 對象狀態 JVM停止運行時 軟引用 內存不足時進行回收 緩存 內存不足 弱引用 對象不被引用時回收 緩存 GC運行后 虛引用 對象被回收時 管理控制精確內存穩定性 unknown
強引用(Strong Reference)
永不回收。
強引用就是在程序代碼之中普遍存在的,類似Object obj = new Object()
這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。
弱引用(Soft Reference)
重點回收對象。
弱引用也是用來描述非必需對象的,被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。
軟引用(Weak Reference)
內存將要溢出時才被回收。
軟引用是用來描述一些還有用但並非必需的對象。對於軟引用關聯着的對象,在系統將要發生內存溢出異常之前,將會把這些對象列表回收范圍之中進行二次回收。如果這次回收還沒有足夠的內存,才會拋出內存溢出異常。
虛引用(了解)(Phantom Reference)
虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關系。一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的就是能在這個對象被收集器回收時收到一個系統通知。
常用的弱引用和軟引用
比如在圖片加載框架中,通過弱引用來實現內存緩存。
//實現圖片異步加載的類 public class AsyncImageLoader { //以Url為鍵,SoftReference為值,建立緩存HashMap鍵值對。 private Map<String, SoftReference<Drawable>> mImageCache = new HashMap<String, SoftReference<Drawable>>(); //實現圖片異步加載 public Drawable loadDrawable(final String imageUrl, final ImageCallback callback) { //查詢緩存,查看當前需要下載的圖片是否在緩存中 if(mImageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = mImageCache.get(imageUrl); if (softReference.get() != null) { return softReference.get(); } } final Handler handler = new Handler() { @Override public void dispatchMessage(Message msg) { //回調ImageCallbackImpl中的imageLoad方法,在主線(UI線程)中執行。 callback.imageLoad((Drawable)msg.obj); } }; /*若緩存中沒有,新開辟一個線程,用於進行從網絡上下載圖片, * 然后將獲取到的Drawable發送到Handler中處理,通過回調實現在UI線程中顯示獲取的圖片 */ new Thread() { public void run() { Drawable drawable = loadImageFromUrl(imageUrl); //將得到的圖片存放到緩存中 mImageCache.put(imageUrl, new SoftReference<Drawable>(drawable)); Message message = handler.obtainMessage(0, drawable); handler.sendMessage(message); }; }.start(); //若緩存中不存在,將從網上下載顯示完成后,此處返回null; return null; } //定義一個回調接口 public interface ImageCallback { void imageLoad(Drawable drawable); } //通過Url從網上獲取圖片Drawable對象; protected Drawable loadImageFromUrl(String imageUrl) { try { return Drawable.createFromStream(new URL(imageUrl).openStream(),"debug"); } catch (Exception e) { // TODO: handle exception throw new RuntimeException(e); } } }
Handler 弱引用,防止內存泄漏
public class MainActivity extends AppCompatActivity { private Handler handler ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new MyHandler( this ) ; new Thread(new Runnable() { @Override public void run() { handler.sendEmptyMessage( 0 ) ; } }).start() ; } private static class MyHandler extends Handler { WeakReference<MainActivity> weakReference ; public MyHandler(MainActivity activity ){ weakReference = new WeakReference<MainActivity>( activity) ; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); if ( weakReference.get() != null ){ // update android ui } } } }