JIT 컴파일러는 자주 실행되는 바이트코드를 런타임에 네이티브 머신 코드로 동적으로 변환하여 해석 오버헤드를 줄이고 실행 속도를 높입니다. 이를 통해 메서드 인라이닝 및 ‘핫 패스’ 최적화가 가능해지고, 특정 CPU 기능을 활용한 하드웨어별 최적화 및 단일 스레드 성능 개선이 이루어집니다. 그러나 동적 코드 생성은 메모리 사용량을 증가시키며, Ruby의 높은 동적 특성(유연한 타이핑, 런타임 객체 수정 등)은 정적 타입 언어에 비해 최적화 범위에 한계를 둡니다.
TruffleRuby는 GraalVM 위에 구축된 Ruby 구현체로, GraalVM의 JIT 컴파일러와 Truffle 프레임워크를 활용하여 특히 계산 집약적인 Ruby 프로그램에서 상당한 성능 향상을 이룹니다. 주요 특징으로는 GraalVM JIT 통합을 통한 빠른 Ruby 코드 실행, GVL이 없어 Ruby 코드의 병렬 실행 가능, Java, JavaScript, Python 등 GraalVM 지원 언어와의 로우 오버헤드 다국어(Polyglot) 지원, 대부분의 C 확장 지원, 그리고 다국어 디버거 및 모니터링 도구(VisualVM, CPU Tracer 등) 제공 등이 있습니다. 제한 사항으로는 MRI와 100% 호환되지 않는 부분이 있으며, 특정 레거시 OpenSSL 버전에 대한 의존성 문제가 있을 수 있습니다.
JRuby는 Java Virtual Machine (JVM) 기반의 Ruby 구현체로, CRuby와의 높은 호환성을 목표로 하여 Ruby 개발자들이 기존 코드를 최소한의 변경으로 실행하면서 JVM의 성능, 도구 및 배포 옵션을 활용할 수 있도록 합니다. 주요 특징은 Ruby 스레드를 Java 스레드에 매핑하여 GVL 없이 진정한 스레드 수준 병렬성을 제공한다는 점, Java 클래스를 Ruby 프로그램에서 사용하거나 JRuby를 Java 애플리케이션에 내장할 수 있는 긴밀한 Java 통합, JIT 컴파일러를 통한 높은 성능, 그리고 MB당 초당 요청 처리량이 높아 호스팅 비용 절감에 유리한 낮은 메모리 사용량입니다. 제한 사항으로는 대부분의 JVM이 안전하게 fork될 수 없기 때문에 fork()
를 지원하지 않으며, JVM에 내장된 기능 부족으로 Continuations를 지원하지 않는다는 점이 있습니다.
성능 벤치마크 (Optcarrot 사용): NES 에뮬레이터 Optcarrot를 활용한 벤치마크 결과, TruffleRuby (GraalVM JVM 모드)가 가장 높은 FPS를 기록하여 최고의 성능을 보였으며, MRI + YJIT가 그 뒤를 이었습니다. JRuby는 초기 성능은 다소 낮았으나, 여러 번 실행 후 안정화된 성능을 보였습니다. 이는 JVM 기반 최적화가 장기 실행 애플리케이션에서 더 효과적이라는 점을 시사합니다.
고급 JIT 컴파일러가 Ruby 생태계에 미치는 영향: YJIT의 발전은 MRI의 경쟁력을 유지시키고 있으며, TruffleRuby와 JRuby의 존재는 개발자들이 애플리케이션의 특정 요구사항(JVM 통합, 네이티브 실행 속도, Ruby 생태계와의 호환성 등)에 따라 최적의 Ruby 구현체를 선택할 수 있도록 합니다. 이러한 다양성은 성능 문제로 인해 개발자들이 덜 선호하는 언어로 전환할 필요성을 줄여주며, Ruby가 다양한 워크로드에서 실행 가능한 강력한 선택지로 남아있도록 합니다. 특히 2023년 Aaron Patterson이 YJIT가 C 확장을 능가하는 성능을 보일 수 있음을 시연한 것은 고급 JIT 컴파일러가 Ruby의 경쟁 우위를 재정의하고 있음을 보여줍니다.
ZJIT 컴파일러는 2025년 5월에 도입된 새로운 JIT 컴파일러로, 더 접근하기 쉽고 커뮤니티 친화적인 컴파일러 아키텍처를 목표로 합니다. YARV 바이트코드를 직접 저수준 IR(LIR)로 컴파일하는 대신, 고수준 SSA 기반 중간 표현(HIR)을 사용하고, 한 번에 하나의 기본 블록 대신 전체 메서드를 컴파일하는 등의 아키텍처적 차이점을 가집니다. 아직 초기 단계이지만, 더 많은 개발자가 Ruby의 성능 개선에 기여할 수 있는 협업의 문을 열어준다는 점에서 중요한 의미를 가집니다.