스프링 어플리케이션 메모리 구조
스프링 어플리케이션 서버 구동 시 메모리들은 어떻게 사용하고 있을까요?
스프링 어플리케이션 서버 구동 시 메모리들은 어떻게 사용하고 있을까요?
JVM(Java Virtual Machine)가 OS에서 실행되어 있어야지만 스프링 어플리케이션을 구동 할 수 있습니다.
스프링에서 실행되는 빈 객체, 스레드 풀 등이 JVM 메모리에 올라가게 됩니다.
힙 메모리
JVM에서 가장크게 차지하는 메모리는 힙 메모리입니다. 스프링에서 실행되는 주요 객체들을 힙 메모리에 저장하고 있습니다.
스프링 빈 객체
스프링에서 어노테이션이나 xml로 정의한 스코프(bean, component, service)가 싱글톤으로 힙 메모리 저장됩니다.
사용자 정의 객체
사용자가 정의한 클래스가 new로 생성한 객체들이 힙 메모리에 저장됩니다.
DB 커넥션 풀
어플리케이션에서 성능을 위해 커넥션 풀을 이용하여 DB 연결하게 되는데 풀 사이즈 만큼 객체를 생성하여 힙 메모리에 저장됩니다.
스레드 풀
스레드 객체를 생성하여 힙메모리 저장하여 요청을 처리합니다.
힙 메모리에 저장되어 있는 객체들은 더 이상 사용하지 않으면 GC 통해 힙 메모리에서 삭제 됩니다.
스택 메모리
Client에서 요청이 오면 스레드 풀에 있는 스레드가 스택 메모리에 메소드, 지역 변수, 매개 변수 등이 스택 프레임에 쌓여 메모리에 저장됩니다. 요청된 작업이 끝나면 사용한 스택 메모리 영역은 제거되고 스레드 풀에 있는 스레드는 반환되어 다른 요청이 올 때 까지 대기(idle)상태가 됩니다.
메타스페이스
.java 파일이 컴파일된 .class 파일을 로드하는 시점에 파일에 대한 메타데이터가 메모리에 저장됩니다.
메타데이터에는 클래스 이름, 메서드 시그니처(매개변수 타입, 리턴 타입), 상수 풀, static 변수, 인터페이스 정보 등이 있습니다.
🤔 스택 메모리와 메타스페이스 차이가 뭘까요?
메타스페이스는 로드 시 파일에 대한 메타데이터를 저장하고 있고 스택 메모리는 스레드 요청 시점에 필요한 값들을 저장하고 있습니다.
아래 예제처럼 메타스페이스와 스택 메모리를 구분 할 수 있습니다.
1 2 3 4 5 public class Test { public int add(int a, int b) { return a + b; } }클래스 로드 시(메타스페이스)
- Test 클래스 정보
- add(int, int) 메서드 시그니처
- return 타입
- 상수 풀
add(3,5) 메소드 호출 시(스택 메모리)
- add 스택 프레임으로 생성되어 스택 메모리에 저장됩니다.
- 지역변수
a=3,b=5할당- return 주소 등록
3+5계산- return 값 스택에 저장
메모리 확인 방법 및 모니터링
JDK에서 제공하는 명령어로 확인하기
jps, jmap, jhat 라이브러리로 JVM으로 실행되는 프로세스의 정보 및 메모리를 확인 할 수 있습니다.
jps(Java Virtual Machine Process Status Tool)
JVM으로 실행중인 프로세스 정보를 확인할 수 있습니다.
jmap(Java Memory Map)
JVM으로 실행 중인 메모리 맵 정보 확인할 수 있습니다.
jmap 명령어
jmap -clstats <pid>: 클래스 로더 통계jmap -finalizerinfo <pid>: Finalizer 큐에 남아있는 객체 목록jmap -histo[:옵션] <pid>: 힙에 존재하는 객체들의 클래스별 개수와 메모리 크기 통계jmap -dump:<옵션> <pid>: 힙 메모리 덤프(.hprof) 파일 생성live: 현재 살이 있는 객체에 대한 집계all: 모든 객체에 대한 집계format=b: 바이러니 형식file=<file>: 덤프 파일 저장gz=<number>: 압축 레벨 지정 (1=빠름, 9=최대 압축)- example:
jmap -dump:live,format=b,file=heapdump.hprof 19289로 현재 살아 있는 객체에 대한 바이러리 힙 메모리 파일 생성
jstat(Java Virtual Machine Statistics Monitoring Tool)
jstat에는 다양한 옵션을 제공하고 있어서 JVM에 gc, 힙 메모리, 클래스 로딩 상태를 실시간으로 정보를 확인 할 수 있습니다.
-class: 클래스 로딩/언로딩 통계. 로딩된 클래스 수, 로딩된 바이트 크기, 언로딩된 수-compiler: JIT(Just In Time) 컴파일러 통계. 컴파일된 메서드 수, 총 시간-gc: GC 통계 요약. Yong, Old, Metasapce, GC 횟수/시간-gccapacity: 메모리 크기 정보. 현재 크기, 최대 크기, 커밋된 용량-gccause: GC 발생 원인을 포함한 통계. 마지막 GC 원인, 다음 예정된 GC 원인-gcmetacapacity: metaspace 크기 정보-gcnew: New 영역(Eden, Survivor) GC 통계-gcnewcapacity: New 영역 크기 정보-gcold: Old 영역 GC 통계-gcoldcapacity: Old 영역 크기 정보-gcutil: 각 영역의 사용률, GC 횟수/시간 통계-printcompilation: JIT(Just In Time) 컴파일된 메소드 목록 출력
🤔 JIT 컴파일러는 뭘까요?
class 파일을 기계어로 컴파일을 하게되는데 같은 소스를 매번 컴파일하게 되면 속도가 느려지게 됩니다. 이러한 문제를 해결하기 위해 JIT 컴파일러가 같은 코드를 컴파일 이후 캐싱 처리를 하여 수정된 부분된 다시 컴파일하여 캐싱된 코드를 사용합니다. 매번 컴파일하는 방식보다 성능이 10~20배정도 개선되었습니다
모니터링 툴을 이용하여 확인하기
VisualVM은 JVM 정보를 확인 할 수 있는 명령어들을 이용하여 GUI로 시각화된 정보를 확인 할 수 있습니다.
실제 운영 중인 서버들도 원격 연결을 이용하여 모니터링도 가능해서 시스템 개선이 필요할 때 메모리/GC/CPU 정보들을 분석할 수 있습니다.





