티스토리 뷰

반응형

젊은 사람들의 특권일 수도 있고, 모르니까 용감한 걸 수도 있습니다만, 어쨌든 대한민국 한정 절대적 1위인 Java는 많은 욕을 먹을 수밖에 없는 위치에 있습니다. 그 중에는 높은 메모리 사용량과 실행파일 용량, 그리고 이로 인해 docker로 대표되는 컨테이너 환경에 친화적이지 않다는 것이 빠지지 않고 등장합니다.

 

2. 높은 메모리 사용량, 실행파일 용량, 컨테이너 비친화적

A. 높은 메모리 사용량

사실 이 내용은 Java 사용자라면 반박할 수 없는 사실이기도 합니다. Java는 메모리를 직접 개발자가 손댈 수 없게 하고 사용된 객체(Object)는 쓰레기 정리(Garbage Collection, 줄여서 GC)라는 기법을 이용해 자동으로 제거하기 때문에 제거되기 전까지는 메모리를 점유하고 있기 때문에 메모리 사용량이 C와 같이 직접 메모리를 할당받고 반납(free)하는 언어들에 비해 높습니다. 하지만, 최근까지 새롭게 나오고 있는 개발언어들은 대부분 GC를 채용하고 있습니다. NSA에서도 메모리 안정성을 위해 Java와 같은 언어를 추천하고 있으며, 이 주장에 반박하는 C++의 아버지인 비야네 스트롭스트룹(비야네 스트롭스트룹 - 위키백과)조차 그의 홈페이지에서 GC가 반드시 나쁜건 아니라고 할 정도이니까요(Stroustrup: FAQ, 물론 저의 영어 실력이 짧고 프로그래밍 내공이 부족하여 오해하고 있는 것일 순 있습니다). 어쨌든 GC를 도입하는 가장 큰 문제는 개발자 모두가 비야네 스트롭스트룹 옹이나 리누즈 토팔즈 옹과 같이 달인의 경지에 오른 사람이 아니기에 메모리 할당부터 해제까지 완벽하게 하여 보안상 문제 없이 코딩하기도 힘들고, 잘못 사용된 메모리 문제로 인하여 시스템이 완전히 정지하는 문제를 완벽히 해결하기 쉽지 않기 때문입니다. 그래서 Java는 GC를 도입하였고, GC하면 Java이고 Java하면 GC가 먼저 언급되게 된 것이라 볼 수 있습니다. 이 말은 가장 오랫동안 그리고 많은 개발자들을 통해 GC가 개발되고 수정되고 사용되어 왔으며, 그래서 타 언어에 비해 가장 발달한 GC를 할 수 있다는 믿음을 가질 수 있게 되었다는 의미이기도 합니다. 심지어 GC가 발생할 때 짧게나마 시스템이 멈출 수 있다는 오래된 GC의 문제 역시 어떻게든 해결할 수 있는 부분이 되었습니다.

B. 실행파일 용량

Java로 개발된 프로그램은 보통 class라는 확장자 이름을 가진 파일들을 생성하고 이를 묶어 jar 혹은 war라는 확장자 이름으로 합쳐져 사용됩니다. 이렇게 생성된 파일은 최근에는 보통 fatJar라고 하는 기술을 통해 실행 가능한 모든 라이브러리를 포함해서 만들어져 한 줄의 명령을 통해 실행이 가능해집니다.

하지만, 이렇게 만들어진 파일은 용량이 큽니다. 이유는 Java는 처음 나올 때부터 JIT이라는 개념을 도입하였기 때문입니다. JIT은 실행 시 최적화를 하는 방식이라고 설명하는 문서들도 있는데, 쉽게 말해 Java로 개발된 내용을 각 컴퓨터의 OS가 인식하는 결과물로 변환해서 사용하는 것이 아니라, 각 OS에 맞는 Java의 가상환경(Java Vertual Machine, JVM)을 설치하고, Java 파일은 JVM에서 실행 가능한 class 파일로 변환한 뒤, 실행 시 JVM이 class 파일을 읽어 OS에 맞게 최적화를 하여 동작하도록 하는 방식입니다. 즉, 대부분의 Java 개발자는 개발하는 장비가 Windows, Linux, MacOS 어떤 것이든 상관없이 개발할 수 있고, 생성된 파일을 다른 OS로 가져가 그대로 실행해도 큰 문제 없이 실행이 가능하다는 것을 보장받는다고 생각하면 됩니다. C나 C++와 같은 컴파일을 하는 언어는 각 OS에서 실행 가능한 컴파일러를 통해 컴파일을 하여 그 OS에 맞는 결과물을 만들어야 합니다. 이렇게 만들어진 파일은 다른 OS에서는 실행이 불가능합니다. 다만 컴파일 시 해당 언어에 대해 최적화가 되기 때문에 실행속도가 Java에 비해 빠릅니다. Python이나 node와 같은 인터프리터(스크립트) 언어들은 실행 때마다 한줄씩 해석하여 실행되기 때문에 실행속도가 느립니다. Go(고랭)와 같이 여러 OS에 맞는 실행파일을 어디서든 만들 수 있는 언어도 개발되었으나, 각 언어별로 생성해야 하기 때문에 여러 OS을 지원하는 프로그램을 만들 때 실행속도가 느리다는 단점이 있었습니다.

이런 Java의 특징은 최근까지 특히나 웹사이트를 만드는 일에서 최고의 효율을 보장해주었고, 개발자의 OS와 상관없이 고객사 등의 서버 환경에 맞는 JVM만 잘 설치해주면 큰 수정 없이 실행이 가능했기 때문에 편리함을 제공해줬습니다. JIT을 사용하기에 실행 시에 최적화가 이루어져 Reflection 기능을 이용한 프래임워크 사용이 원할하고, 프로필 기반 실행 등 편리함도 제공되고 있습니다.

C. 컨테이너 비친화적, 신기술 적용이 느림 점

하지만, 최근에 Container 기반 환경의 대중화로 인해 Java에 불명예가 씌여졌습니다. 위에서 언급한 비대한 메모리 사용량과 실행파일 용량 모두 비용 등에 문제를 일으켰기 때문입니다. 거기에 초기 실행시간 역시 오래 걸린다는 문제가 있습니다(JIT의 특성). 혹자는 Warm-up이 필요한 특성도 얘기하고 있습니다(특정 기능을 처음 실행할 때 메모리에 내용이 올라가있지 않기 때문에 느리게 느껴짐). 이러한 점들이 컨테이너 비친화적이라고 얘기하고 있고, 관리의 편리성(전 아닌데...)이나 MSA 구현의 편리함 등의 이유로 Kubernetes 환경을 선호하다보니 Java는 정말 B**L S**T이라고 하는 분들도 있습니다(웃긴게 대부분 주니어급).

그런데, 이런 얘기는 대부분 맞는 이야기이고 저 역시 동감하는 내용입니다. 타 언어 대비 장점이 있으면 반드시 단점이 존재하는 법이죠. Java가 완전무결한 언어일 수는 없습니다. 아니, 모든 언어들 역시 완전무결할 수 없습니다. 그래서 사용자가 많고 점유율이 높을 수록 안티의 존재는 당연히 있죠.

 

문제는...Java는 변화에 민감한 언어가 아니라는 겁니다. 어떤 언어처럼 개발자(혹은 개발자들)가 필요하다면 그냥 쓱~하고 기능을 포함하지 않는다는 겁니다. 기능을 바로 적용하는 언어 중에는 동일한 기능을 하는데 함수 이름에 따라 매개변수의 순서가 다르다던지...와 같이 중복기능이 많고 어수선한 느낌도 주고 NULL을 판정하느 기준도 뭔가 이상하게 되어 있어서, 이로 인해 프로그램 내 버그(프로그래머가 의도하지 않은 동작)가 내포되어 있기도 합니다. Java는 JCP라는 기구에서 JSR이라고 하는 기준에 의해서 각 버전에 맞는 기능을 먼저 정의하고, 의결기구 내 투표를 통해 기능구현이 확정되면 비로소 기능이 구현되고, TCK라는 툴에 의해 제대로 동작되는지 확인이 되면 정식으로 공개되는 흐름을 가집니다. 그렇기 때문에 JCP에서 치열한 토론이 거듭되는 기능에 대해서는 예정일정보다 훨씬 나중에 기능이 포함된다던가, 심하면 정식버전 배포가 수 년간 미뤄지기까지 합니다. 그래서, 새로운 기능 혹은 패러다임의 적용이 늦게 되는 경우가 많습니다. 여담이지만, 반면에 이런 언어의 특성에 의해 Java는 기업시장(Enterprise)에서도 안정적으로 도입이 가능한 언어로 여겨집니다. 무료이고 여러 OS에서 많은 수정 없이 사용할 수 있는데 언어 자체의 안정성도 뛰어난 것이 지금까진 Java 외엔 딱히 없었기 때문입니다. 그래서 전자정부 등 대규모 정보처리 사업들이 우후죽순 같이 생기던 시점에 Java를 도입한 사업들이 많았고, 전자정부 프래임워크와 같은 물건도 생겼다고 생각합니다.

 

결론

어쨌든 시대의 흐름은 컨테이너(Container, docker가 대표적)를 이용해 서비스를 제공하는 것이 보편화 되었기 때문에 Java의 단점은 크게 부각되었고, Java Development Kit을 만드는 Sun(이제는 Oracle)에서도 이러한 문제를 알고 있었습니다. 그래서 나온 것이 GraalVM이고 AOT(Ahead-of-Time)입니다. 사실 Java는 JDK나 JRE을 이용해 JVM(Java Virtual Machine)에서 동작하기 때문에 컨테이너를 만들어 그 안에서 동일한 환경을 만드는 일을 굳이 할 필요는 없다고 생각합니다만, 그건 저 같이 프로그래밍과 인프라, DevOps와 같은 것들의 지식이 모두 일정수준 이상에 오른 사람들에게나 그런 얘기고, 개발한 결과물을 사용하는 사람들이 반드시 저와 같을 수는 없습니다. 그래서 Java 진영에서도 컨테이너에 알맞는 Java 결과물을 만들기 위해 오래 전부터 준비해왔고, Oracle은 GraalVM이라는 컴파일러를 제공하여 Native Compile이라는 형태로 OS에 맞는 실행파일을 생성하도록 지원하고 있습니다. Spring Boot라는 Java의 절대강자도 최근에 지원하고 있으며, Spring에게 자리를 내줬던 J2EE도 MicroService 지원을 대폭 향상해서 MicroProfile, QuarKus 같은 프래임워크를 통해 지원하고 있습니다. 이렇게 생성된 Native 파일은 생성한 OS에 맞게 실행 시 분석이 아닌 사전 분석을 통해 일반적인 타 언어의 바이너리 실행파일과 유사하게 동작합니다. 초기 부팅시간은 매우 빠르며, 메모리 점유도 적게 합니다. GC를 싫어하는 사람들에겐 대안이 될 수 없겠지만, GC 중 가장 진보된 능력을 제공하고 있습니다. 단점은 Windows에서 특히 Compile하기 어렵지만(전 한 번도 성공 못해봤습니다. docker Ubuntu와 MacOS에서만 해봤습니다), 그리고 JIT이 아니기에 Reflection와 Profile와 같은 기능의 사용에 있어서 제약도 있고 까다로운 부분이 생기지만, 컨테이너 환경의 대중화가 Java는 어울리지 않는다는 인식이 줄어들게 만들 것임은 분명해 보입니다.

 

어쨌든...마지막으로...

반박 시... 여러분 말이 맞습니다.
반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함