요즘 디자이너와 함께 하는 개발 연합동아리 NEXTERS에서 앱을 만드는데 OOM에 대해서 공부하게 되었다.

JVM이 메모리 관리를 해주는데도 불구하고 OOM이 발생한다는 것,

그래서 개발자 세션을 진행하는 nc소프트 행님에게 말했더니 직접 세션을 하면서 발표 해보라는거...


부들부들...


PPT를 만들면서, Tistory에 포스팅 해야 겠다 생각해서 포스팅 하고 있다ㅋㅋ

보통 OOM은 

프로그램이 메모리를 할당 후 해제하지 않아서 생기는것으로 C언어 동적할당(malloc)후 free를 하지 않았을 경우에 발생한다.

-> 단 한번의 예제(학습) 프로그램에서는 상관 없지만 , 서버나 계속 돌아가야 되는 프로그램에서 누적된 Memory의 Leak은 프로그램을 사망하게 한다.


GC는! 동작방식에 따라 다양한 종류가 있다.(Java , C# , 등등등) 이 GC들은 공통적으로 2가지 작업을 수행하는데,


1. 힙 내의 객체들 중에서 가비지를 찾아낸다.

2. 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다.


GC는 참조카운트가 0이 되면 메모리를 회수하는 걸로도 유명하죠.



Java의 GC는 객체(이하 인스턴스)에 대해서 Reachability 개념을 사용합니다. 

인스턴스에 대해서 참조카운트가 0이 아니라면 Reachable. 참조카운트가 0이라면 unReachable.


GC는 참조 카운트가 0인 인스턴스들 즉, unReachable에 대한 객체에 대해서만 메모리를 회수합니다.


Java 1.2버전부터는 개발자들이 Reachable한 인스턴스와 unReachable한 객체에 대해서 컨트롤 할 수 있게 클래스를 제공해줬는데요.


그 클래스들은 StrongReference,SoftReference , WeakReference , PhantomReference입니다.


보통 PhantomReference는 많이 사용하지 않고 , 스트롱 레퍼런스, 윜 레퍼런스, 소프트 레퍼런스를 많이 사용하는데요(LRU 구현 등)


일단 클래스들 설명에 앞서, 코드 조금 보고 갈게요.



해당하는 코드는 저희 HATT앱의 MainActivity의 코드 일부분 입니다.


대충 어디서 메모리 릭이 발생하는지 감이 오시나요??ㅋㅋ



보통 Android를 개발하는 개발자들은 어쩔 수 없이 this를 보내주는 경우가 있죠.

이럴 경우 메모리 릭이 발생하여 나중가면 프로그램이 사망하는 경우가 생깁니다.


그 이유는, this를 보내주는 객체에선 Context객체를 필요로 하는 상황이 발생했는데 this를 보내줌으로써, Context와 함께 

해당하는 Activity에 있는 멤버필드에 있는 객체들과 여러 참조들을 같이 보내주게 됨으로써 메모리 릭이 발생하는 것입니다.


이해가 되나요?

말이 어려웠으면 댓글 달아주세요. 자세히 설명해 드리겠습니다.


WeakReference<Sample> obj = new WeakReference<Sample>(new Sample());

Sample ex = obj.get();

ex = null;

위와 같은 코드로

인스턴스를 생성 시, WeakReference에 전달인자로 넘겨주어 인스턴스를 생성합니다.

그런 후, WeakReference의 get()메소드를 이용하여 객체 잠조를 가져와 필요한 작업을 한 뒤, 객체 참조를 가지고 있는 변수에 null을 대입해 줍니다.


이해를 돕기 위하여 이미지를 통하여 설명하면,


 

위 그림은 

WeakReference<Sample> obj = new WeakReference<Sample>(new Sample());

Sample ex = obj.get();

까지 작성한 코드입니다.


SampleObject는 StrongReference와 WeakReferenceObject에 연결되어 있는데요, 이 경우는 StrongReference가 더 강력하여, GC는 StrongReference로 취급합니다.


하지만


ex=null을 하게 되면




다음과 같이 SampleObject는 Weakly reachable형태가 됩니다.


다음과 같이 되면, GC는 SampleObject를 unReachable 인스턴스로 취급하여 메모리 회수를 하게 됩니다.




이런 방식을 사용하여, this를 보내줄 때도, Activity가 이동하게 되어서, 인스턴스를 사용하지 않게 된다면,

StartActivity or StartActivityForResult 메소드를 호출하기 전에, null을 대입해 주는것입니다.



그럼 OOM을 막을 수 있겟죠.



오늘은 너무 늦어서 여기까지 작성하고 주말에 다른 API도 마저 작성하겠습니다.



출처


라이언 이모티콘 : 카카오톡 이모티콘.

+ Recent posts