2017-05-25 42 views
0

訂閱非主線程上的Observable並將該Observable添加到CompositeSubscriptions時,我們的Android應用程序中存在內存泄漏。這是代碼導致內存泄漏的塊:CompositeSubscription在使用新線程訂閱Observable時泄漏內存

  mSubscriptions.add(Observable.just(imageBytes) 
       .subscribeOn(Schedulers.newThread()) 
       .map(bytes -> { 
        YuvImage yuvimage = new YuvImage(bytes, ImageFormat.NV21, mPreviewWidth, mPreviewHeight, null); 
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        yuvimage.compressToJpeg(new Rect(0, 0, mPreviewWidth, mPreviewHeight), 100, baos); // Where 100 is the quality of the generated jpeg 
        byte[] jpegArray = baos.toByteArray(); ... 
       }) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .subscribe(result -> { 
        ... 
       }, error -> Timber.e(error))); 
    } 

內部地圖中使用的存儲器是永遠不會被釋放(除非我們稱之爲CompositeSubscriptions.clear())。如果一切都在主線程上完成,或者如果我們不將Observable添加到我們的CompositeSubscription,則沒有內存泄漏。這兩種解決方案都不是一種選擇。請告知如何以適當的方式做到這一點,所以我們不會耗盡內存。

回答

1

我不確定我是否理解正確,但如果您在訂閱時無法正確管理,則始終可能從應用程序中獲取內存泄漏。

所有的拳頭 - 你不應該使用Schedulers.newThread(),因爲它每次當你訂閱observable時會產生新的線程。您應該使用Schedulers.io()而不是使用newThread()。它需要現在可用的線程池。

其次,您應該展示如何管理訂閱。

onCreate(Bundle saveInstanceState){ 
subscriptions.add(...); 
} 

onPause(){ 
subscriptions.unsubscribe(); 
subscriptions.clear(); 
} 

如果你需要認識到訂閱應該被退訂,你可以用一個簡單的Map<String, Subscription> map你把

map.put("TAG_FOR_SUBSCRIPTION", yourSubscription) 
+0

感謝您的答覆。我們使用調度程序,newThread僅僅是一個例子。無論我們使用自己的調度程序,rx庫還是新線程提供的調度程序都會發生內存泄漏。我們正在根據生命週期清理複合訂閱,這是行得通的。上面的塊稱爲每秒幾次,它處理圖像,因此消耗大量內存。它沒有任何生命週期事件泄漏,所以它沒有關係。快速修復將清除onCompleted中的這個可觀察對象的每個訂閱,但這不能解決根本原因。 – njosa

+0

我想知道爲什麼內存不會被GC釋放,當我們在非主線程上執行此操作時,它在主線程上執行時完美工作。 – njosa

+0

'onCompleted'事件是有風險的,因爲你不能確定這個事件會被永遠調用。 –