본문 바로가기
Android/Java

Android WeakReference

by DnaJ 2019. 1. 31.
반응형

Android WeakReference


WeakReference는 Reference를 상속받고 있다. 

Reference는 메모리 누수를 막기 위해서 사용된다.


Reference의 종류는 StrongReference, PhantomReference, SoftReference, WeakReference가 있다.

StrongReference를 제외하고 Reference<T>를 상속받고 있다. Reference는 garbage collector와 연관이 있다.

참조 - android developer : https://developer.android.com/reference/java/lang/ref/Reference


Reference의 뜻을 네이버에서 찾아보았다.

Reference

1. (… 에 대해) 말하기, 언급; 언급 대상, 언급한 것

2. (정보를 얻기 위해) 찾아봄, 참고, 참조

3. 문의, 조회


우리가 원하는 뜻이 포함되어 있다. 

2. (정보를 얻기 위해) 찾아봄, 참고, 참조


우리가 주목을 해야하는 뜻은 참조다.

우리는 객체를 참조를 하기 위하여 Reference라는 것을 사용하게 된다.


우리가 흔히 사용하는 것은 StrongReference(강한 참조)WeakReference(약한 참조)다.

StrongReference 는 new 를 사용해서 생성된 객체다. 거의 대부분이 StrongReference로 생성이 되었을 것이다.


여기서 잠시 강한 참조와 약한 참조의 차이점이 잘이해가 안된다고 하면 Deep Copy(깊은복사)와 Shallow Copy(얕은복사)를 생각하면 조금은 쉽게 이해가 갈것이다.

StrongReference는 Deep Copy, WeakReference는 Shallow Copy와 비슷하다고 생각하면 될것이다.

하지만 다른점은 대상이 Copy는 메모리, Reference는 참조 라는 것이다.


StrongReference와 WeakReference비교


생성

class TestObject {

public TestObject() {


}
}


StrongReference와 WeakReference의 생성하는 것부터 비교를 하기 위해서 TestObject를 작성했다.

public class TestClass {
private TestObject strong;
private WeakReference<TestObject> weak;

public TestClass() {
// StrongReference 생성
strong = new TestObject();

// WeakReference 생성
weak = new WeakReference<>(new TestObject());

// WeakReference에 등록한 객체를 가져온다

TestObject weakObject = weak.get();

}
}


WeakReference<T> object = new WeakReference<>(new <? extends T>)

필자는 TestObject를 WeakReference로 만들었다.

WeakReference<TestObject> weak = new WeakReference<>(new TestObject());



Garbage Collection (GC) 동작이후 객체 상태

Android Developer에서는 Garbage Collector와 많은 연관이 있다고 나와있다. 왜그런지 살펴보자.


Garbage Collection쓰레기 수집은 동적 할당된 메모리 영역 가운데 더 이상 사용할 수 없게 된 영역을 탐지하여 자동으로 해제하는 기법이다. 

참조 wikipedia: https://ko.wikipedia.org/wiki/%EC%93%B0%EB%A0%88%EA%B8%B0_%EC%88%98%EC%A7%91_(%EC%BB%B4%ED%93%A8%ED%84%B0_%EA%B3%BC%ED%95%99)


GC가 발생하게 되면 사용할 수 없게된 영역해제하게 된다. (GC가 발생해도 곧바로 정리가 되는 것은 아니다.)

여기서 StrongReference와  WeakReference차이가 발생하게 된다.


StrongReferenceGC가 발생해도 객체가 해제되지 않는다.


WeakReferenceGC가 발생하면 참조하고 있는 객체가 해제된다. 


WeakReference로 생성한 객체는 WeakReference.get()으로 가지고 와도 null이 나오는 경우가 있다. 


객체가 해제된다는 것은 사용가능한 공간(Memory)를 확보한다는 것이다.

만약 사용하지 않는 객체들을 계속 해제를 하지 않으면 결국 OOM(Out Of Memory)이 발생할 수 있다.


결국 StrongReference는 GC가 발생해도 객체가 해제되지 않기 때문에 OOM의 발생 시킬수 있다.

하지만 WeakReference는 GC가 발생하면 객체가 해제되기 때문에 OOM의 위험성을 줄일 수 있다.


WeakReference는 GC가 발생하면 참조하는 객체가 해제되기 때문에 WeakReference객체가 null이 아니지만 

참조를 하고 있는 객체는 null이 나올 수 있는 위험성을 지닌다.


public TestClass() {
// StrongReference 생성
strong = new TestObject();

// WeakReference 생성
weak = new WeakReference<>(new TestObject());

// GC 강제 실행
System.gc();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// weak 는 null이 아니다
// weakObject 는 null이다
TestObject weakObject = weak.get();
}
}, 1000);

}


위의 코드에서 강제로 GC를 실행 시키고 있다. (Test를 위하여......)

GC가 실행된 이후 WeakReference참조된 객체는 해제가 된다.


위의 코드에서 weak라는 변수는 GC가 발생해도 해제가 되지 않는다.

하지만 weak에서 참조를 하고 있는 Object(TestObject)는 해제가 되기 때문에 weakObject변수의 값은 null이 된다.


value weak is not null

value weakObject is null


null이 나오는 이유

WeakReference를 생성하게 되면 참조가 된 객체는 ReferenceQueue에 등록이 된다.

ReferenceQueue : 참조 대기열. 객체의 참조 변화에 따라 변경이 된다. ReferenceQueue에 등록이 되면 GC에 의해 객체가 해제 될 수 있다. 

       (SoftReference로 만든 경우는 객체가 해제되지 않을 수 있다. ->  나중에 따로 포스팅을 하겠다.)


ReferenceQueue에 등록된 WeakReference는 Garbage Collector가 사용이 되지 않는다고 판단을 하여 GC가 발생하면 객체를 해제해버린다.



반응형

댓글