NOTE이 글은
자바의 정석
,인파님의 블로그
의 글을 인용하여 작성하였습니다. 아카이빙 용도로 제가 보려고 작성하였기 때문에 더 자세한 내용은 자바의 정석과 블로그를 참고해주시면 감사드리겠습니다.
자바
자바는 썬 마이크로시스템스(Sun Microsystems, Inc. 이하 썬)에서 개발하여 1996년 1월에 공식적으로 발표한 객체지향 프로그래밍 언어이다.
자바의 가장 중요한 특징은 운영체제(Operating System, 플랫폼)에 독립적이라는 것이다. 자바로 작성된 프로그램은 운영체제의 종류에 관계없이 실행이 가능하기 때문에, 운영체제에 따라 프로그램을 전혀 변경하지 않고도 실행이 가능하다.
이러한 장점으로 인해 자바는 다양한 기종의 컴퓨터와 운영체제가 공존하는 인터넷 환경에 적합한 언어로써 인터넷의 발전과 함께 많은 사용자층을 확보할 수 있었다. 또한 객체지향개념과 기존의 다른 프로그래밍언어, 특히 C++의 장점을 채택하는 동시에 잘 사용되지 않는 부분은 과감히 제외시킴으로써 비교적 배우기 쉽고 이해하기 위한 간결한 표현이 가능하도록 했다.
자바는 풍부한 클래스 라이브러리(Java API)를 통해 프로그래밍에 필요한 요소들을 기본적으로 제공하기 때문에 자바 프로그래머는 단순히 이 클래스 라이브러리만을 잘 활용해도 강력한 기능의 자바 프로그램을 작성할 수 있다.
지금도 자바는 꾸준히 자바의 성능을 개선하여 새로운 버전을 발표하고 있으며, 모바일(J2ME)이나 대규모 기업환경(J2EE), XML 등의 다양한 최신 기술을 지원함으로써 그 활용영역을 넓혀 가고 있다.
JVM(Java Virtual Machine)
JVM은 ‘Java virtual machine’을 줄인 것으로 직역하면 ‘자바를 실행하기 위한 가상 기계’라고 할 수 있다. 가상 기계라는 말이 좀 어색하겠지만 영어권에서는 컴퓨터를 머신(machine)이라고도 부르기 때문에 ‘머신’이라는 용어대신 ‘컴퓨터’를 사용해서 ‘자바를 실행하기 위한 가상 컴퓨터’라고 이해하면 좋을 것이다.
‘가상 기계(virtual machine)‘는 소프트웨어로 구현된 하드웨어를 뜻하는 넓은 의미의 용어이며, 컴퓨터의 성능이 향상됨에 따라 점점 더 많은 하드웨어들이 소프트웨어화되어 컴퓨터 속으로 들어오고 있다. 그 예로는 TV와 비디오를 소프트웨어화한 윈도우 미디어플레이어라던가, 오디오 시스템을 소프트웨어화한 윈앰프(winamp) 등이 있다.
이와 마찬가지로 ‘가상 컴퓨터(virtual computer)‘는 실제 컴퓨터(하드웨어)가 아닌 소프트웨어로 구현된 컴퓨터라는 뜻으로 컴퓨터 속의 컴퓨터라고 생각하면 된다.
자바로 작성된 애플리케이션은 모두 이 가상 컴퓨터(JVM)에서만 실행되기 때문에, 자바 애플리케이션이 실행되기 위해서는 반드시 JVM이 필요하다.
일반 애플리케이션의 코드는 OS만 거치고 하드웨어로 전달되는데 비해 Java애플리케이션은 JVM을 한 번 더 거치기 때문에, 그리고 하드웨어에 맞게 완전히 컴파일된 상태가 아니고 실행 시에 해석(interpret)되기 때문에 속도가 느리다는 단점을 가지고 있다. 그러나 요즘엔 바이트코드(컴파일된 자바코드)를 하드웨어의 기계어로 바로 변환해주는 JIT컴파일러와 향상된 최적화 기술이 적용되어서 속도의 격차를 많이 줄였다.
위 그림에서 볼 수 있듯이 일반 애플리케이션은 OS와 바로 맞물려 있기 때문에 OS종속적이다. 그래서 다른 OS에서 실행시키기 위해서는 애플리케이션을 그 OS에 맞게 변경해야한다. 반면에 Java 애플리케이션은 JVM하고만 상호작용을 하기 때문에 OS와 하드웨어에 독립적이라 다른 OS에서도 프로그램의 변경없이 실행이 가능한 것이다. 단, JVM은 OS에 종속적이기 때문에 해당 OS에서 실행가능한 JVM이 필요하다.
그래서 썬에서는 일반적으로 많이 사용되는 주요 OS용 JVM을 제공하고 있고, 이렇게 함으로써 자바의 중요한 장점 중의 하나인 “Write once, run anywhere. (한 번 작성하면 어디서든 실행된다.)”이 가능하게 되는 것이다.
JDK, JRE
JDK
JDK는 자바 개발키트(Java Development Kit)의 약자로 개발자들이 자바로 개발하는 데 사용되는 SDK 키트라 생각하면 된다. 그래서 JDK안에는 자바를 개발 시 필요한 라이브러리들과 javac, javadoc 등의 개발 도구들을 포함되어 있고, 개발을 하려면 자바 프로그램을 실행도 시켜줘야 하기 때문에 뒤에서 배울 **JRE(Java Runtime Environment)**도 함께 포함되어 있다.
TIP💡 SDK란?
Software Development Kit (소프트웨어 개발 키트) 로, 하드웨어 플랫폼, 운영체제 또는 프로그래밍 언어 제작사가 제공하는 툴이다. 키트의 요소는 제작사마다 다르다. SDK의 대표적인 예로, 안드로이드 스튜디오 등이 있다. 이 SDK를 활용하여 애플리케이션을 개발할 수 있다.
JDK는 버전별로 특징과 기능이 다르며, Java 8, Java 11, Java 17 등 LTS(Long Term Support) 버전이 많이 사용된다. Oracle JDK 외에도 OpenJDK, Amazon Corretto, Azul Zulu 등 다양한 벤더에서 JDK를 제공하고 있어 필요에 맞게 선택할 수 있다.
JRE(Java Runtime Environment)
JRE는 자바 실행환경(Java Runtime Environment)의 약자로서, JVM과 자바 프로그램을 실행(동작)시킬 때 필요한 라이브러리 API를 함께 묶어서 배포되는 패키지 이다. 이외에도 자바 런타임 환경에서 사용하는 프로퍼티 세팅이나 리소스 파일(jar 파일)을 가지고 있다. JRE는 기본적으로 JDK에 포함되어 있기 때문에 JDK를 설치하면 함께 설치된다. 기존에는 개별적으로 설치가 가능했지만 JDK11 버전부터는 따로 제공되지 않는다고 한다.
간단히 정리하자면, Java로 프로그램을 직접 개발하려면 JDK가 필요하고, 컴파일 된 Java 프로그램을 실행시키려면 JRE가 필요하다고 보면 된다.
자바 애플리케이션 실행 과정
- Java Compiler가 JAVA로 작성된 소스 코드 .java 파일을 .class 파일인 Byte Code로 컴파일한다.
(단, 해당 코드는 직접 CPU에서 동작할 수 있는 코드가 아니다. 정확히 말하면 가상머신 JVM이 이해할 수 있는 코드이다.) - 이제 이 Byte Code를 기계어로 변환시키기 위해 가상 CPU가 필요한데, 이것이 **JVM(Java Virtual Machine)**의 역할이다.
- Class Loader는 JVM 내에서 .class 파일을 로드하고 검증하는 역할을 담당한다.
- Loading: 클래스 파일을 찾아서 JVM의 메모리에 로드
- Linking: 검증(Verification), 준비(Preparation), 해석(Resolution) 과정을 수행
- Initialization: 클래스 변수들을 적절한 값으로 초기화
- Execution Engine은 Class Loader에 의해 메모리에 로드된 Byte Code를 실제 **기계어(Binary Code)**로 변환하고 실행한다.
- Interpreter: Byte Code를 한 줄씩 해석하고 실행
- JIT(Just-In-Time) Compiler: 자주 실행되는 코드를 네이티브 코드로 미리 컴파일하여 성능을 향상
- Garbage Collector: 더 이상 사용되지 않는 객체를 메모리에서 제거
- 이렇게 JVM에 의해 변환된 기계어는 바로 CPU에서 실행되어 사용자에게 서비스를 제공한다.
NOTE💡바이트 코드란?
바이트코드(Bytecode, portable code, p-code)는 특정 하드웨어가 아닌 가상 컴퓨터에서 돌아가는 실행 프로그램을 위한 이진 표현법이다. 하드웨어가 아닌 소프트웨어에 의해 처리되기 때문에, 보통 기계어보다 더 추상적이다.
역사적으로 바이트코드는 대부분의 명령어가 1바이트 크기의 명령 코드(opcode)와 필요한 매개변수로 구성되어 있어서 이런 이름을 갖게 되었다. 바이트코드는 특정 컴퓨터 하드웨어에 덜 의존적이면서도 쉽게 해석할 수 있는 코드를 만들고자 하는 프로그래밍 언어들이 중간 결과물로 사용한다.
사람이 작성한 원본 소스 코드와 비교하면, 바이트코드는 더 단순하고 컴퓨터가 처리하기 좋은 형태이다. 예를 들어 변수가 지역변수인지 전역변수인지와 같은 정보가 바이트코드에는 이미 명확하게 표시되어 있어 소스 코드를 직접 분석하는 것보다 실행 속도가 빠르다.
바이트코드 프로그램은 보통 한 번에 하나씩 명령어를 읽고 실행한다. 이런 방식의 인터프리터는 다양한 컴퓨터 환경에서 쉽게 작동할 수 있다. 바이트코드 프로그램들 중 JIT(Just-In-Time) 컴파일러가 있는데, 이는 프로그램 실행 중에 바이트코드를 해당 컴퓨터가 직접 이해할 수 있는 기계어로 변환한다. 이 방법은 바이트코드 자체의 이식성은 유지하면서도 실행 속도를 높일 수 있다.
예를 들어, 자바나 C# 프로그램은 보통 바이트코드로 먼저 변환되어 저장되고, 실행할 때 JIT 컴파일러가 이를 해당 컴퓨터의 기계어로 바꿔준다. 이 과정에서 프로그램 시작 시 약간의 지연이 생기지만, 한번 변환되고 나면 인터프리터 방식보다 훨씬 빠르게 실행된다.
주요 버전 차이
자바는 1996년 첫 공식 출시 이후로 꾸준히 발전해왔으며, 각 주요 버전마다 새로운 기능과 개선사항이 추가되었다. 특히 LTS(Long Term Support) 버전들은 기업 환경에서 안정적으로 오래 사용할 수 있도록 장기 지원이 제공된다.
각 LTS 버전 특징을 알아보자.
Java 8 (LTS, 2014년)
- 람다 표현식(Lambda Expressions): 함수형 프로그래밍을 지원하여 간결한 코드 작성 가능
- 스트림 API(Stream API): 컬렉션을 함수형으로 처리할 수 있는 기능이 추가
- 메서드 레퍼런스: 람다 표현식을 더 간결하게 표현할 수 있는 방법 도입
- 디폴트 메서드: 인터페이스에 구현체를 가진 메서드를 정의 가능
- Optional 클래스: null 처리를 보다 안전하게 할 수 있는 클래스 제공
- 새로운 날짜/시간 API: 기존 Date와 Calendar의 문제점을 개선한 새로운 API 추가
- PermGen 제거와 Metaspace 도입: 메모리 관리 방식이 개선
- 지원 기간: 2030년 12월까지 지원
Java 11 (LTS, 2018년)
- var 키워드 확장: 람다 표현식의 매개변수에서도 var 키워드 사용 가능
- HTTP 클라이언트 API: 기존의 HttpURLConnection을 대체하는 새로운 HTTP 클라이언트가 추가
- String 클래스 개선: isBlank(), lines(), strip() 등 새로운 메서드 추가
- 파일 API 개선: Files.readString(), Files.writeString() 메서드 추가
- 컬렉션 변환 개선: Collection.toArray(IntFunction) 메서드 추가
- Reactive Streams API 통합: 비동기 스트림 처리를 위한 표준 API가 통합
- ZGC(실험적): 대용량 메모리를 위한 새로운 가비지 컬렉터 도입
- 모듈 시스템 개선: Java 9에서 도입된 모듈 시스템 개선
- 제거된 기능: Java EE 모듈, CORBA 모듈, JavaFX가 JDK에서 분리
- Oracle JDK 유료화: 상업적 사용 시 라이선스 비용이 발생하게 되어 OpenJDK 사용이 증가
- 지원 기간: 2026년 10월까지 지원
Java 17 (LTS, 2021년)
- 봉인 클래스(Sealed Classes): 상속 가능한 클래스를 명시적으로 제한하는 기능 추가
- 레코드(Records): 불변 데이터 객체를 위한 새로운 타입 표준화
- 패턴 매칭(프리뷰): switch 문에서 타입 패턴 매칭 기능이 프리뷰로 제공
- 텍스트 블록: 여러 줄의 문자열을 쉽게 작성할 수 있는 기능 개선
- 외부 메모리 접근 API(프리뷰): 자바 힙 외부의 메모리에 접근할 수 있는 API 도입
- Vector API(프리뷰): SIMD(Single Instruction, Multiple Data) 연산을 지원하는 API 추가
- 강화된 의사 난수 생성기: 보안이 향상된 난수 생성 기능 추가
- Stream.toList(): 스트림을 리스트로 쉽게 변환할 수 있는 메서드 추가
- ZGC와 Shenandoah GC 개선: 가비지 컬렉터의 성능 개선
- 지원 기간: 2029년 10월까지 지원
Java 21 (LTS, 2023년)
- 가상 스레드(Virtual Threads): 경량 스레드를 통한 동시성 처리 성능이 크게 개선
- 스위치 패턴 매칭 표준화: 스위치 문에서 타입과 패턴 매칭 기능이 정식으로 추가
- 레코드 패턴(Record Patterns): 레코드 타입에 대한 패턴 매칭 지원 추가
- 문자열 템플릿(프리뷰): 문자열 내 표현식을 쉽게 포함시키는 기능이 프리뷰로 제공
- 구조적 동시성(Structured Concurrency): 동시성 코드의 가독성과 안정성을 향상시키는 기능 추가
- 외부 함수 및 메모리 API: 네이티브 코드와의 상호 작용 개선
- SequencedCollection 도입: 컬렉션의 시퀀스 관련 연산 개선
- 세대별 ZGC: 향상된 가비지 컬렉션 성능 제공
- 보안 관리자 제거 계획: 레거시 보안 메커니즘 단계적 제거 시작
- 지원 기간: 2031년 9월까지 지원
OpenJDK와 Oracle JDK
Java 11부터 Oracle JDK는 상업적 사용 시 라이선스 비용이 발생하게 되었다. 이에 따라 많은 기업들이 무료로 사용할 수 있는 OpenJDK로 전환하였고, Amazon Corretto, Azul Zulu, AdoptOpenJDK(현 Eclipse Adoptium) 등 다양한 OpenJDK 기반 배포판이 등장하였다.
자바 릴리스 주기
Java 9부터 6개월마다 새로운 버전이 출시되는 릴리스 주기로 변경되었다. 그리고 약 3년마다 LTS 버전이 출시되어 장기 지원을 제공한다.