자바 코드를(.java) 컴파일하여 .class *바이트 코드로 만들면 이 바이트 코드가 자바 가상 머신 환경에서 실행됩니다.
하나의 바이트 코드(.class)로 모든 플랫폼에서 동작이 가능
-> 플랫폼에 국한되지 않음
ex) C언어로 작성한 norman.c 파일이 있을 때, 윈도우 컴파일러로 컴파일하면 norman.exe 가 만들어집니다.
(이 파일은 윈도우에서 컴파일되어 윈도우에서만 실행됨)
이 파일은 윈도우 OS에선 동작하지만 리눅스 OS에선 동작하지 않습니다.
-> norman.exe 파일을 리눅스에서 실행하려면 크로스 컴파일 해서 리눅스 OS에 맞는 실행 파일을 새로 만들어야 합니다.
하지만, Java의 경우 컴파일을 하면 norman.class 파일이 생성됩니다.
이 바이트 코드는 JVM이 운영체제에 맞는 실행 파일로 바꿔줍니다.
즉, Java에서는 JVM을 사용하기에, 각자의 플랫폼에 맞게 컴파일을 따로해줘야 할 필요가 없습니다.
"Java는 어떠한 플랫폼에 영향을 받지 않는다."
위에 내용을 통해 Java가 플랫폼에 영향을 받지 않는다는 것을 알 수 있습니다.
하지만, JVM은 플랫폼에 영향을 받습니다.
정리하자면
Java는 플랫폼에 종속적이지 않지만, JVM은 종속적이다
라고 할 수 있습니다.
1. .java 파일을 컴파일하여 .class 바이트 코드 생성
2. Class Loader를 통해 Runtime Data Area로 로딩
3. RDA에 로딩된 바이트 코드들은 Execution Engine을 통해 해석
4. 해석된 바이트 코드는 RDA의 각 영역에 배치되어 수행, 이 과정에서 Execution Engine에 의해 Garvage Collector의 작동과 스레드 동기화 이루어짐
자바는 동적으로 클래스 읽어오므로, 런타임에서야 모든 코드가 JVM과 연결됨.
-> 동적으로 클래스를 로딩해주는 역할을 하는 것이 Class Loader
.java 파일을 컴파일하면 .class 파일이 생성되는데, Class Loader는 .class 파일을 묶어서 RDA에 적재합니다.
클래스 로더에 의해 JVM으로 로드된 .class들은 RDA의 Method Area에 배치되는데, 배치된 이후에 JVM은 Method Area의 바이트 코드들을 실행 엔진(Execution Engine)에 제공하여 실행시킵니다.
즉, 로드된 바이트코드들을 실행하는 런타임 *모듈이 실행 엔진(Execution Engine) 입니다.
-> 실행 엔진은 명령어 단위로 읽어서 실행
JVM은 가비지 콜렉터(Garbage Collector)를 사용하여 사용하지 않는 메모리를 자동으로 회수합니다.
따라서 개발자가 따로 메모리를 관리하지 않아도 됩니다.
즉, 가비지 콜렉터는 Heap 메모리 영역에 생성된 객체들 중에 참조되지 않은 객체들을 탐색 후 제거하는 역할을 합니다.
GC 역할을 수행하는 스레드 제외한 나머지 스레드들은 일시정지 상태가 됩니다.
JVM의 메모리 영역으로 자바 애플리케이션 실행할 때 사용되는 데이터들 적재하는 영역
모든 스레드가 사용
스레드 마다 하나씩 생성
클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보 등과 같은 각종 필드 정보들과 메서드 정보, 데이터 타입 정보, static 변수 등이 생성되는 영역
new 키워드로 생성된 객체와 배열이 생성되는 영역
주기적으로 GC가 제거
Heap Area는 효율적인 GC를 위해 3가지 영역으로 나뉩니다.
1. Young Generation
2. Old (Tenured Generation)
3. Permanent
Eden 영역은 자바 객체가 생성되자마자 저장되고, 생긴지 얼마 안되는 객체가 저장되는 공간입니다.
이 영역에 어느정도 데이터가 쌓이면 참조정도에 따라 Survivor의 빈 공간으로 이동 or 회수됩니다.
YG 영역(Eden + Survivor)이 차게되면 또 참조정도에 따라 Old 영역으로 이동 or 회수됩니다.
Young Generation과 Tenured Generation 에서의 GC를 Minor GC라고 합니다.
Old 영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 GC 실행됩니다.
이 작업은 시간이 오래 걸리고 이 때 GC를 실행하는 스레드를 제외한 모든 스레드는 작업을 멈추게 됩니다.
-> 이 작업을 "Stop-the-World"라고 합니다.
그리고 Stop-the-World 발생하고 Old 영역의 메모리를 회수하는 GC를 Major GC 라고 합니다.
지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역
스레드가 생성될 때마다 생성되는 영역
-> 현재 스레드가 실행되는 부분의 주소와 명령 저장하고 있는 영역
JVM은 바이트 코드를 명령어 단위로 읽어서 해석합니다.
-> Interpreter 방식과 JIT 컴파일 방식 두 가지를 혼합하여 사용
Interpreter 방식은 바이트코드를 한 줄씩 해석, 실행하는 방식으로 초기 방식인데 속도가 느리다는 단점 존재합니다.
이 느린 속도를 보완하기 위해 나온 것이 JIT(Just in Time) 컴파일 방식입니다.
바이트 코드를 JIT 컴파일러를 이용해 실행하는 시점에서 각 OS에 맞는 네이티브 코드로 변환하여 속도를 개선합니다.
하지만, 이 방식도 비용이 소모되므로 JVM은 모든 코드를
JIT 컴파일러 방식으로 실행하지 않고, Interpreter 방식을 사용하다가 일정 기준을 넘어가면 JIT 컴파일 방식으로 명령어를 실행합니다.
컴퓨터의 운영체제 소프트웨어 상에서 실행되고 클래스 라이브러리 및 특정 Java 프로그램이 실행해야 하는 기타 리소스를 제공하는 소프트웨어 계층
개발자들이 Java로 프로그램을 만들 수 있도록 다양한 기능을 제공하는 키트
-> 컴파일러, JRE, JVM 등의 도구들을 가지고 있습니다.
단어 정리
모듈 : 프로그램을 구성하는 구성 요소로, 관련된 데이터와 함수를 하나로 묶은 단위
바이트 코드(Bytecode) : 고급 언어로 작성된 소스 코드를 가상머신이 이해할 수 있는 중간 코드
네이티브 코드(Nativecode) : CPU와 운영체제가 직접적으로 실행할 수 있는 코드
참고
많은 것을 배웠습니다, 감사합니다.