퉁탕퉁탕 만들어보자

Java의 GC 본문

Computer/Android

Java의 GC

호숀티 2022. 4. 17. 16:44
반응형

가끔 검증자로부터 이슈가 올라온다. 그 중 Memory관련된 이슈는 보통.. "버벅거린다" 이슈와 "앱이 강제종료되었다" 이슈다.

"강제종료되었다" 는 Log를 보면 FATAL Exception인 경우가 사실 거의없다. 개발단계에서 쉽게 검출되기 때문에 잡고나간다. 그런데도 강제종료되는 케이스를 보면 매우 드물지만, LMK가 내 앱을 죽여버린것이다. 그러면 이제 "메모리부족이라 LMK가 죽인것임 내 앱이 잘못된게 아님" 으로 이슈를 닫으면 된다.

 

"버벅거린다" 이슈는 사실 잡기 어려운데, 전반적인 성능개선이 필요하기 때문이다. 그렇지만 이것도 가끔 log보면 내 문제가 아닌경우가 있는데 "OOM"로그가 잔뜩 찍혀있는 경우가 있다. 이 경우에는 android GC가 돌고있는 상황이라 느려진것으로 보고 "전반적으로 메모리가 부족한 상황이라 GC가 돌고있고 그래서 버벅거리는 것임" 으로 이슈를 닫으면 된다. 보통 이 두 이슈 둘다 저가단말에서 주로 발생하기 때문에 발생한 모델명까지 저가단말이면 100프로다.

 

그러면 Java GC와 Android GC 그리고 OOM과 LMK, 그리고 앱메모리 성능개선 대해서 알아보고자 한다.

 

1. JAVA GC

JAVA는 c나 c++과 다르게 메모리를 할당하고나서 free를 명시적을 안해주고 좀 자유롭게 사용을 한다. 대신 메모리가 부족한 상황이 오면 GC process가 돌면서 메모리 정리를 해준다.

이걸 멈추게 할수는 없고 또 되게 expensive한 작업이라, GC가 돌고있는 동안에 버벅일수있다.

 

방식은 Mark and Sweep 이라고 부르는데, 우선 GC가 스택의 모든 변수를 스캔하면서 각각 어떤 오브젝트를 레퍼런스 하고 있는지 Mark 한다. 오브젝트가 레퍼런스하고 있는 오브젝트도 mark 한다.

그리고 mark 되어있지 않은 모든 오브젝트들을 힙에서 제거하는 과정이 Sweep 이다. 그런데 그러면 서로 cyclic 하게 reference하고있는 object는 어떻게 처리할까? 둘다 stack으로부터 reference가 없으면 둘다 mark된다.

* 그런데, heap 중간 중간 sweep된다면? 큰 allocation이 어렵다. 그래서 sweep with compaction 작업을 한다.

 

그런데, 모든 object들을 전부 mark하고 sweep하고 compaction하는게 사실 너무 비효율적이다. 점점 더 많이 allocation될 수록 전부다 돌면서 mark하고 sweep하는데 시간이 많이 소모되게된다.

object의 수명을 체크해보면, 굉장히 많은 object들이 빨리 사용되고 빨리 죽는다. 오래 사는 object들은 굉장히 소수다. 그래서 성능향상을 위해서 "세대"를 분리한다.

The Young Generation(젊은 세대) - 새 object들이 할당되는 곳이다. young generation이 꽉차면, "minor GC"가 돌게된다. minor collection은 되게 많이 죽여버림으로써 optimize된다. 몇몇 살아남은 친구들은 나이가 차면 old generation으로 이동하게 된다. 

 

Stop the World Event - 모든 minor GC는 "Stop the World" 이벤트다. 즉 GC가 완료될때까지 모든 application thread들이 멈추게 된다.

 

The Old Generation(나이든 세대): 오랫동안 살아남은 object를 저장하는 공간이다. 대체로 threshold 나이를 정해놓고 그 이상 나이가 차면 young에서 old로 옮겨진다. 최종적으로 old generation에 있는 것들도 collect가 되긴 해야한다. 이것을 "major GC"라고 한다. 

 

Major GC 또한 Stop the World event다. 대체로  major collection 가 훨씬 느린데, 이유는 전부 살아있는 object들 이기 때문이다. 따라서, major GC는 최소화되어야한다. 또한 "Major GC"의 Stop the world 이벤트의 길이는, old generation space를 청소하는데 사용하는 GC의 종류에 따라서 차이가 난다.

 

Permanent generation에는 어플리케이션에서 사용되는 클래스와 메서드를 설명하기 위해 JVM이 필요로 하는 메타데이터가 포함된다. 어플리케이션에서 사용 중인 클래스를 기반으로 런타임 시 JVM에 의해 채워진다. 또한 Java SE 라이브러리 클래스 및 메서드를 여기에 저장할 수 있다.

JVM이 클래스가 더 이상 필요하지 않고 다른 클래스를 위한 공간이 필요할 수 있음을 발견하면 클래스가 수집(언로드)될수있다.  Permanent generation도 전체 가비지 수집에 포함된다.

 

Android GC는 다음편에서 계속!

https://hosyonty.tistory.com/entry/Android-%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC

728x90
반응형