JAVA

JAVA의 단점 - 속도문제

Hangyu_Choi 2020. 11. 29. 16:33

1. JAVA의 속도 문제

여기서 잠시 유의할 점은, 느리다는 내용은 대부분 C/C++, Pascal, Fortran 같은 네이티브 바이너리 코드를 만드는 언어와 비교했을 때의 이야기입니다. 자바가 C/C++ 보다 2~3배 느리다고 하지만 다른 고수준 언어들에 비해서는 그리 떨어지지 않습니다. 1.4 버전에서 JIT 컴파일 지원이 돼서 많이 빨라졌습니다. 특히 인터프리터/스크립트 언어는 구조적으로 자바에 비해서도 훨씬 느립니다. 예를 들어 요즘 인기 있는 Python은 C보다 수십 배 느리고, 그나마 빠르다고 하는 JavaScript도 자바에 비해서 2배 정도 느립니다.

 

또한 속도 관련 문제는 하드웨어의 성능이 점점 좋아지고 메모리 가격이 떨어지면서 희석되고 있습니다. 처음 자바가 나왔을 때인 1995년만 하더라도, 느린 성능 때문에 그다지 많이 쓰이지는 않을 것이라고 예상했지만 현재 자바가 가장 많이 사용되는 곳 중 하나는 안정성과 일정 수준 이상의 성능이 요구되는 서버입니다. 자바가 네이티브 코드보다 느리지만 대부분의 상황에서는 큰 문제가 되지 않습니다.

 

1-1. JVM 로딩 속도 문제

자바의 심각한 단점 중 하나는, 실행하는 과정에서 JVM(Java Virtual Machine)이 반드시 완벽하게 로딩되어야 하기 때문에 프로그램의 초기 시작 시간이 완전한 이진 코드로 컴파일된 프로그램을 실행하는 것에 비해 오래 걸리는 것입니다. 단적인 예로, 아무것도 안 하고 콘솔 화면에 달랑 "Hello, World!"라고 찍기만 하는 프로그램이 실행되는 데에도 thread가 10개쯤 뜨는데, 특히 그 프로그램에 AWT, Swing, SQL 같이 불필요한 기능을 끌어들이는 것은 매우 심각한 문제입니다. 이 문제는 런타임 자체가 아직 모듈화 되지 않았다는 점에서 기인합니다.

 

하지만 요즘 같은 고사양 컴퓨터에서는 아주 많은 라이브러리를 끌어오는 것이 아니라면 체감상 차이는 크게 나지 않습니다. 또한 Java 9부터는 드디어 런타임 라이브러리를 모듈화하고 있으므로, 필요한 모듈만 끌어서 프로그램을 짤 수 있습니다.

 

1-2. 가상 머신 바이트코드 실행 속도 문제

C/C++, Pascal, Fortran과 같은 언어와 달리, 자바는 바이트코드로 된 프로그램을 실행하기 위해 운영체제와 프로그램 사이에 JVM이라는 두꺼운 계층이 하나 더 자리 잡게 됩니다. 그리고 바이트코드는 실시간으로 각 타깃 플랫폼용 기계어로 번역되어 실행됩니다. 이로 인해 네이티브 바이너리 코드를 출력하는 언어와 비교하여 실행 속도와 성능에 일정 부분 손실이 발생할 수밖에 없습니다. AWT, Swing 같은 GUI 라이브러리를 사용할 때도 심각하게 느린 것을 체감할 수 있습니다. 이런 문제점을 썬 마이크로시스템즈도 곧 깨달았고, 최초 발표에서 2년 후인 1998년부터 JIT 컴파일러를 JVM에 내장하여 성능이 상당 부분 개선되었습니다. 하지만, 그만큼 메모리가 뒷받침해줘야 합니다. 현재는 보통 같은 기능/알고리즘을 실행하는 데 C++ 보다 2~3배 정도의 시간이 더 필요하다고 알려져 있습니다. 이 부분은 꽤 초기부터 지속적으로 개선되어 왔기 때문에 현재 실행 속도 자체에 대한 이슈는 예전에 비해 많이 줄어든 편이긴 합니다.

 

이 문제는 Java 9에서 '선행 컴파일'이라는 이름으로 개선될 예정입니다. JIT 컴파일로 실행과 동시에 컴파일을 하는 게 아니라 기존의 정적 컴파일처럼 바이트코드를 미리 기계어로 번역하면, 컴파일 속도는 다소 느려지지만 실행 속도는 빨라지게 됩니다. 물론 컴파일 한 번으로 여러 플랫폼에서 동일하게 실행시키는 건 불가능해집니다.

 

1-3. 가비지 컬렉션에 의한 실행 지연 문제

가비지 컬렉션에 의한 메모리 프리징 현상이 초반부터 지속적으로 자바를 괴롭혔습니다. 멀쩡하게 동작해야 할 프로그램이 순간적으로 뚝 뚝 끊기는 듯한 현상이 발생하는 것이죠. 오늘날 자바의 문제는 바이트코드 변환으로 인한 속도 저하보다 이 가비지 컬렉션의 영향이 더 크다고 할 수 있습니다. 이러한 문제점은 가비지 컬렉션을 지원하는 다른 프로그래밍 언어들도 마찬가지이긴 하지만 실행 속도와 함께 자바 초기부터 꾸준히 문제로 꼽혀온 것으로, 버전이 올라갈 때마다 다양하게 개선되어 왔습니다.

 

Java 8부터는 메모리 누수를 일으키던 메서드 영역의 PermGen Area를 제거하여 static 인스턴스와 리터럴 문자열도 GC의 대상이 되도록 바뀌었으며, 클래스, 메서드, 배열의 메타 정보는 동적 리사이징이 가능한 Metaspace로 이동시켜 시스템 힙 영역에 저장됩니다. 덕분에 JVM 힙 영역의 공간이 늘어나고 PermGen Area를 스캔/삭제할 필요가 없어져 GC의 성능이 대폭 향상되었습니다.