공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!! 포스팅 내용이 찾아주신 분들께 도움이 되길 바라며 더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^
|
메모리 누수
일반적으로 참조가 완료되었지만 할당한 메모리를 해제하지 않아서 발생.
강한 참조의 경우 GC가 메모리에서 객체를 제거할 수 없기 때문에
라이프 사이클에 맞게 객체 참조를 끊어주어야 사용하지 않는 메모리 해제 가능.
시스템 전체 성능에 영향을 주는 요소이므로 중요하게 관리해야함.
메모리 누수 예제
package park.sunggyun.thomas.rxandroidnetworkex;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.observers.DisposableObserver;
public class MainActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
start();
}
private void start() {
Observer<String> observer = new DisposableObserver<String>() {
@Override
public void onNext(String s) {
textView.setText(s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
Observable.<String>create(emitter -> {
emitter.onNext("Hello RxAndroid");
emitter.onComplete();
}).subscribe(observer);
}
}
정상적으로 동작하는 코드입니다. BUT 메모리 누수가 있는 예제입니다.
Observable은 안드로이드의 Context를 복사하여 유지하고
onComplete(), onError() 함수가 호출되면 내부에서
자동으로 unsubscribe() 를 호출합니다.
구독자가 텍스트 뷰를 참조하기 때문에, 액티비티가 비정상 종료될 경우
텍스트 뷰가 참조하는 액티비티는 종료되어도 GC의 대상이 되지 못합니다.
=> 메모리 누수 발생.
위 같은 문제를 해결하는 방법에 대해 보겠습니다.
Disposable 인터페이스를 이용한 명시적 자원해제
onCreate()에서 subscribe()를 호출하면 onDestroy()에서 메모리 참조를 해제하고
onResume()에서 호출하면 onPause()에서 해제합니다.
이 방법을 라이프 사이클에 맞에 설정해주면 됩니다.
package park.sunggyun.thomas.rxandroidnetworkex;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
public class MainActivity extends AppCompatActivity {
private Disposable disposable;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
start();
}
private void start() {
DisposableObserver<String> observer = new DisposableObserver<String>() {
@Override
public void onNext(String s) {
textView.setText(s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
disposable = Observable.<String>create(emitter -> {
emitter.onNext("Hello RxAndroid");
emitter.onComplete();
}).subscribeWith(observer);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!disposable.isDisposed()) {
disposable.dispose();
}
}
}
RxLifeCycle 라이브러리 사용
compose()를 이용해 RxLifeCycle 라이브러리 적용.
먼저 dependencies{} 에
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
를 추가해줍니다.
그리고 activity는 RxAppCompatActivity를 상속받아주면 됩니다.
package park.sunggyun.thomas.rxandroidnetworkex;
import android.os.Bundle;
import android.widget.TextView;
import com.trello.rxlifecycle2.android.ActivityEvent;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import io.reactivex.Observable;
public class MainActivity extends RxAppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
start();
}
private void start() {
Observable.<String>create(emitter -> {
emitter.onNext("Hello RxAndroid");
emitter.onComplete();
}).compose(bindUntilEvent(ActivityEvent.DESTROY))
.subscribe(textView::setText);
}
}
CompositeDisposable 클래스 사용
이 클래스를 사용하면 생성된 모든 Observable을 안드로이드 라이프 사이클에 맞춰서
한 번에 모두 메모리 해제를 할 수 있습니다.
package park.sunggyun.thomas.rxandroidnetworkex;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import io.reactivex.Observable;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
public class MainActivity extends AppCompatActivity {
TextView textView;
CompositeDisposable cDisposable = new CompositeDisposable();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
start();
}
private void start() {
Disposable disposable = Observable.<String>create(emitter -> {
emitter.onNext("Hello RxAndroid");
emitter.onComplete();
}).subscribe(textView::setText);
cDisposable.add(disposable);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!cDisposable.isDisposed()) {
cDisposable.dispose();
}
}
}
이상입니다.
다음 포스팅에서는 RxJava 디버깅에 대해 공부합니다.