hola 개발

[ JVM ] 왜 같은 API인데 시간이 지날수록 빨라질까? (Spirng) 본문

자바

[ JVM ] 왜 같은 API인데 시간이 지날수록 빨라질까? (Spirng)

hola. 2026. 4. 17. 10:18

 개인 프로젝트로 대규모 쿠폰 발급 시스템을 만들어서 부하 테스트를 하다보면 최초 부하 테스트 보다 그 이후에 부하 테스트 시 응답 속도 결과가 빨라진 것을 자주 목격 했습니다. 단순히 최적화가 되서 그런가보다 라고 생각했지만, 어떻게 어떤 이유로 최적화를 시키는지 JVM관점에서 공부 해봤습니다.

 

[ JVM 입장에서 보는 Spring 생성과 요청 처리 과정  ]

# Spring 생성

 spring 애플리케이션 실행 시, JVM은 classloader를 통해 .class 파일들을 가져와 바이트코드 분석, 클래스 구조 생성을 한 후 MetaSpace에 클래스 메타 데이터를 저장합니다. 그리고 검증,준비,참조 연결 단계를 거친 후 static 변수 초기화 및 static block을 실행합니다. 이후 JVM은 main thread를 생성되면서 main thread 전용 stack/Pc Register/Native Stack이 만들어지고 main() 메서드가 실행되면서 springApplication.run()이 실행됩니다 .

 

 main() 안에서 SpringApplication.run()이 실행되면 Spring Boot가 시작되고, ApplicationContext가 생성되며 refresh()가 호출된다. 이 과정에서 Component Scan이 수행되어 @Component, @Service, @Controller 같은 클래스들이 탐색되고, 이를 기반으로 BeanDefinition이라는 “객체 설계도”가 만들어져 BeanFactory에 등록됩니다.

 

 그 다음 BeanFactory가 createBean()을 호출하면서 실제 객체를 생성하는데, 이때 new가 실행되어 Heap에 Bean 객체가 생성되고, 이후 의존성 주입(@Autowired), 초기화(@PostConstruct), AOP 프록시 적용이 순차적으로 이루어집니다.

 

# 요청 처리 과정

클라이언트 요청이 오면 worker thread의 stack에는 controller/service/repository 호출 프레임이 쌓이고, Execution Engine은 그 프레임 안의 bytecode를 interpreter/JIT으로 실행하게 됩니다.

 

 JVM은 처음엔 interpreter로 bytecode를 실행하다가 실행 빈도가 높은 메서드를 JIT이 native code로 컴파일하여 이후에는 더 빠르게 실행하게 됩니다. 즉,초기 부하 테스트가 느린 이유는 Interpreter 기반 실행 + JIT profiling 부족 상태이고, 이후 테스트가 빨라지는 이유는 JIT이 hot method를 native code로 최적화했기 때문입니다.