JVM은 자바 프로그램을 실행하기 위한 가상 머신입니다. javac에 의해 변환된 바이트코드를 읽어 실행하는 일종의 머신입니다.
그러면 어떻게 읽고, 어떻게 실행하는 건지 좀더 자세히 내부 동작에 대해 알아보겠습니다.
Class Loader - Execution Engine - Runtime Data Area
JVM은 크게 세가지 영역으로 나뉩니다.
바이트코드를(.class)를 JVM의 메모리 영역인 Runtime Data Area에 배치시키는 작업을 수행합니다. 클래스 로더는 다음과 같이 3단계로 구성됩니다.
Execution Engine은 클래스 로더를 통해 Runtime Data Area에 배치된 바이트 코드를 명령어 단위로 읽어서 동적으로 실행합니다. 중간레벨인 바이트코드를 기계어로 변경해주는 역할을 합니다.
이때, 인터프리터와 JIT 컴파일러 두 가지 방식을 혼합하여 바이트 코드를 실행합니다.
[참고] 코드캐시 영역이 꽉 찬다면?
-> 코드캐시 영역은 JVM이 시작될 때 설정된 고정 크기이므로 확장이 불가능합니다. 따라서 코드캐시가 꽉 차면 더이상 JIT 컴파일은 이루어지지 않고 새로운 코드는 모두 인터프리터 모드로만 동작합니다.
JVM의 메모리 영역을 Runtime Data Area라고 합니다. Method, Heap, Stack, PC Register, Native Method Stack 으로 구성되어 있습니다.
OutOfMemoryError
발생StackOverFlowError
발생OutOfMemoryError
발생참고: https://velog.io/@impala/JAVA-JVM-Runtime-Data-Area
Runtime Data Area 영역에서 Stack, PC Register, Native Method Stack은 생명주기가 비교적 짧기 때문에 메모리 걱정을 덜 해도 됩니다.
JVM 메모리에서 Heap 영역에 저장된 인스턴스는 Stack 영역의 참조변수에 의해 가리키고 있습니다. 참조되지 않는 인스턴스는 GC를 통해 메모리에서 제거됩니다.
JVM의 Heap 영역은 아래 두 가지를 전제로 설계되었습니다.
즉, 객체는 대부분 일회성이고 메모리에 오래 남아있는 경우는 적다는 것입니다. 이런 전제를 통해 Heap 영역을 Young/Old 으로 나누었습니다.
GC 모니터링이란 JVM이 어떻게 GC를 수행하고 있는지 알아내는 과정입니다. JVM이 효율적으로 GC를 수행하는지 파악하고, stop-the-world가 언제 일어나고 얼마동안 지속되는지 등의 정보를 알 수 있습니다. GC 모니터링에 문제가 있다면, GC 알고리즘을 변경하거나 GC 튜닝을 진행할 수 있습니다.
OutOfMemoryError
가 발생했다면?JVM 프로그램이 OutOfMemoryError
에러가 발생했다면, 원인을 파악하기 위해 Heap Dump를 분석해야 합니다. -XX:+HeapDumpOnOutOfMemoryError
JVM 옵션을 설정하면 힙덤프 .hprof 파일을 자동으로 생성됩니다.
실시간으로 스냅샷을 생성할 수도 있습니다.
ps -ef | grep java
로 확인해도 되지만,jps
간편한 명령어도 있다.jmap -dump:format=b,file=/my/path/test-heapdump.hprof ${pid}
힙덤프 툴을 이용해 분석합니다. (대표적으로 Memory Analyzer, Visual Vm 이 있다.)
메모리를 가장 많이 점유하는 객체를 파악할 수 있고 의심되는 객체 등을 확인할 수 있습니다.
무분별하게 객체를 생성하거나, reachable 상태를 유지할 경우가 대부분입니다.
따라서 코드레벨에서 주의하고, 적절한 메모리 사이즈를 지정해줍니다.
애플리케이션에 맞는 적절한 메모리 사이즈를 지정해주는 것이 좋다.
-Xmx
: 최대 메모리 사이즈
-Xms
: 초기 메모리 사이즈
G1 GC는 대용량 메모리가 있는 멀티 프로세서 시스템을 위해 제작되었습니다. Stop-the-world를 최소화하도록 설계되었습니다.
Heap 영역을 동일한 크기(기본 2MB)의 Region으로 나누어 논리적으로 구분합니다. 각 Region은 Eden, Survivor, Old 등의 역할을 동적으로 부여받습니다. 새로운 영역도 존재합니다.
이전 GC와 마찬가지로 Eden -> Survivor -> Old 이동의 생명주기를 가집니다.
가비지 비중이 높은 Region을 우선적으로 수집하기 때문에 "Garbage First"라고 합니다.