GC에서 stop the world를 하는 이유가 뭘까?
GC는 안쓰는 인스턴스를 처리하기 전에 반드시 stop the world를 하고 이 순간 모든 애플리케이션 동작이 멈추고 GC는 빠르게 불필요한 인스턴스 메모리를 제거합니다.
실제로 회사에서 인터셉터에서 계속 호출되는 똑같은 형태의 객체가 존재하여 플라이웨이트 패턴을 이용하여 자주 참조되는 인스턴스를 static으로 선언하여 GC 동작이 자주 되는 코드를 개선한 경험이 있었는데요.
GC가 자주 호출 되면 그 만큼 stop the world가 자주 발생하여 사용자 입장에서 느껴질 정도로 애플리케이션 동작이 지연될 수 있다고 한 글을 읽어 이러한 개선을 했던 것입니다. (메모리 측면도 물론 고려하여)
그렇다면 stop the world가 길어질 수록 성능이 떨어지기 때문에 GC 튜닝의 최종 숙제는 결국 stop the world 줄이기일 정도 인데요. 왜 그러면 이러한 치명적인 단점이 있음에도 stop the world를 하고 Garbage 인스턴스들을 처리하는걸까요?
지금부터 이유를 크게 두 가지로 설명 드리겠습니다.
메모리 파편화 (Memory fragmentation)
컴퓨터 시스템에서 메모리 공간을 할당하고 해제하는 과정에서 발생하는 현상입니다. 메모리 파편화는 크게 외부 파편화와 내부 파편화로 나뉘는데 외부 파편화는 메모리 공간이 여러 개의 작은 조각으로 나누어져 사용되어, 충분한 메모리 공간이 있음에도 불구하고 큰 메모리 블록을 할당할 수 없는 경우를 말합니다.
반면에 내부 파편화는 메모리 공간 중 일부가 할당된 뒤 남는 공간이 발생하는 경우입니다. 예를 들어, 8byte의 메모리 블록이 할당 되었는데 10byte 공간으로 할당 받았다면 2byte의 내부 파편화가 발생합니다. 즉 메모리 파편화는 메모리를 효율적으로 사용하는데 있어 치명적으로 작용합니다.
GC도 마찬가지입니다. 할당 된 메모리를 해제 하는 과정에서 메모리 공간이 새로 남는데 이를 해결하기 위해 Compaction이 일어나야합니다. 즉 힙 영역 내의 빈 공간들을 큰 블록으로 만들고 다시 이용할 수 있는 상태로 만들어야하는데 이를 위해 객체를 새로운 주소로 이동 시키고 다시 주소를 참조할 수 있게 해줘야합니다. 그렇기 때문에 stop the world가 필수입니다.
자세히 알고 싶다면 다음 글을 참고 바랍니다.
https://golf-dev.tistory.com/52
객체 일관성
만약 GC가 발생하는 동안 stop the world가 발생하지 않는다면 어떻게 될까요? 메모리 파편화 문제를 제외 하더라도 만약 Garbage Collector가 더 이상 사용되지 않는 객체를 탐지하고 수집하는 작업을 수행하는데, 이 과정에서 메모리 내의 객체들의 상태가 변경될 수 도 있고 다른 스레드가 객체를 참조할 수도 있습니다.
이로서 잘못된 결과나 의도치 않은 오류를 낼 수 도 있습니다. 예를들어 Garbage Collector가 수집하는 객체를 스레드가 동시에 참조했다고 가정하면 나중에 다시 호출 됐을 때 이미 객체는 수집되서 존재하지 않기 때문에 예기친 못한 오류를 만날 수 있고 위 메모리 단편화 문제를 해결하기 위해 Compaction이 발생해서 객체가 이동하는 과정에서 스레드가 의도치 않은 전혀 다른 객체 주소를 참조하여 예상 못한 동작을 일으킬 수 있습니다.
그렇기 때문에 객체 일관성 때문이라도 stop the world는 매우 중요한 역할을 담당한다는것을 알 수 있습니다.
마무리
현재 Java 11로 들어오면서 기본 GC가 G1GC로 바뀌면서 young generation이나 old generation이 아닌 일부 region generation 만 compaction 해주기 때문에 메모리 파편화 현상이 최소화 되었습니다.
하지만 그렇다 하더라도 stop the world 가 자주 발생하면 사용자가 느낄 수 있을 만큼 애플리케이션 동작에 지연이 발생할 수 있습니다. 그렇기 때문에 이를 고려하여 설계 하는 것이 중요한데요.
대표적으로 Heap 메모리 크기가 작으면 Heap 메모리가 부족할 때마다 GC가 동작할 것이고 이는 G1GC도 단일 스레드로 Full GC를 하기 때문에 정말 성능이 느려질 수 있습니다.
때에 따라선 이러한 현상이 발견된다면 Heap 메모리를 늘리는 것도 해결방법입니다.
마침.