전체적인 실행과정을 나타내는 사진이다. 차분히 하나하나 알아보도록 하자
*핵심키워드 Java Complier , JVM , Interpreter , JIT complier
컴파일러는 인간이 사용하는 고레벨언어(source code) 를 기계가 이해 할 수 있는 저레벨 언어(machine code)로 해석해주는 프로그램이다.
소스코드 (compling)-> 목적파일 (Linking)-> 실행파일이 된다.
c, c++ 언어의 목적파일은 바이너리(binary code) 형태를 갖지만, 자바는 바이트 코드를 가진 바이트 파일로 변환된다. 바이트 파일 .class 파일로 변환된다.
cf)
소스파일 : 개발자가 작성하는 고레벨언어인 소스코드로 구성된 파일 ex .java ,*.c
목적파일 : 소스파일을 컴파일해서 생긴 파일 ex) 바이트코드, 바이너리 코드
바이트 파일 (.class) :
바이트 코드로 작성된 .class 파일은 기계가 읽기 편하도록 만들어 놓은 파일이다. 이 파일을 JVM이 읽어들여 실행한다. 클래스 파일을 실행하기 위해서는 필요한 모든.class 파일을 불러들이고, 코드를 검증한 뒤 메모리로 올리는 작업을 수행한다. 만약 클래스가 없거나 오류가 있다면 오류를 발생시키고, 그렇지 않으면 정상 수행한다.
바이너리 코드(이진 코드)는 CPU가 이해할 수 있는 언어, 바이트 코드는 가상머신(ex. JVM)이 이해할 수 있는 언어입니다. 그리고 자바 컴파일러는 JVM이 이해할 수 있도록 소스파일(.java)를 목적파일(.class, 바이트파일)로 변환시켜주는 역할을 합니다.
바이트파일 .class는 최종적으로 실행되는 실행파일이 아니다. java 파일이 실행되려면 자바 컴파일러 다음으로 JVM을 거쳐야 한다.
*cf) 바이너리 코드 vs 바이트 파일 에 대해서 읽어보고 정리해보자
https://kingofbackend.tistory.com/122
JVM (Java Virtual Machine) 프로그램을 실행 하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것으로 컴파일러로 변환된 .class 파일을 class loader를 통해 읽어 들여 자바 API와 함께 실행시킨다.
자바의 장점으로
1. 운영체제의 구애를 받지 않는다.
2. 메모리 관리가 용이하다
위 2가지가 있는데 이를 가능하게 해주는 것이 JVM 이다.
JVM 실행과정
1. Class Loader를 통해 class 파일들을 JVM에 올린다.
2. JVM에 있는 .class 파일들을 (Execution Engine 의 interpreter 와 JIT
complier) 를 통해 해석된다.
3. 해석된 바이트 코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어진다.
로드 : 클래스 파일을 가져와서 JVM의 메모리에 로드합니다.
검증 : 자바 언어 명세(Java Language Specification) 및 JVM 명세에 명시된 대로 구성되어 있는지 검사합니다.
준비 : 클래스가 필요로 하는 메모리를 할당합니다. (필드, 메서드, 인터페이스 등등)
분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경합니다.
초기화 : 클래스 변수들을 적절한 값으로 초기화합니다. (static 필드)
Interpreter는 컴파일러 처럼 고레벨언어를 기계어로 해석해주는 번역 프로그램이다. 컴파일러는 전체 소스코드를 보고 명령어를 수집하고 재구성하는 반면, 인터프리터는 소스코드의 각 행을 연속적으로 분석하며 실행합니다. 때문에 일반적으로 각 행마다 실행하는 인터프리터보다는 컴파일러가 빠르다..
->언핏보면 착각할 수 있는데, 컴파일러를 통해 기계어로 전부 변환된 상태에서 실행되기 때문에 컴파일러 언어가 runtime(실행속도)가 더 빠르다.
-> build(compile) 과정이 없는 인터프리터 언어들은 행별로 해석하면서 실행시켜야 하기 때문에 컴파일 언어의 실행속도보다는 상대적으로 느리다
*cf ) 자바스크립트와 파이썬이 대표적인 인터프리터 언어고, C,C++은 컴파일언어, 자바는 컴파일러와 인터프리터 모두 해당됩니다.
JVM 의 Exectuion Engine 인터프리터를 개선하기 위해 도입된 것이 JIT complier 이다. 인터프리터는 각 행마다 읽어 변환하고, JIT complier는 바이트 코드를 전체를 읽어 한꺼번에 변환한다.
코드 초기에 인터프리터에 의해 시작되고, 해당 코드를 충분히 많이 사용할 경우 JIT 컴파일러에서 컴파일을 수행한다. 초기에 인터프리트 방식으로 바이트 코드를 변환하면서 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 코드가 생성되는 것을 방지합니다.
이렇게 컴파일된 코드를 네이티브 코드라고 부른다. 네이티브 코드는 캐시에 보관되기 때문에 한번 컴파일 된 코드는 빠르게 수행될 수 있다.
유효하지 않는 메모리, 즉 주소를 잃어버려서 사용할 수 없는 메모리를 Garbage를 해제 시켜 다른 용도로 사용할 수 있게 해주는 프로그램이다.
Garbage Collector를 수행할 땐 Garbage Collector를 수행하는 스레드를 제외한 모든 스레드들이 작업을 멈추고, 이후 완료되면 작업을 다시 시작합니다.
C, C++는 사용자가 메모리를 직접 해제해주어야 하지만 자바 같은 경우 Garbage Collector를 이 작업을 수행해줍니다.
주의할점은 메모리 누수까지 잡아주지는 않습니다.
*메모리 누수 : 프로그램 구동 중에 필요치 않은 메모리가 계속해서 점유하고 있는 현상
각 영역별로 조금 더 자세히 조사해볼 필요성을 느꼈다. 대략적인 내용을 알고 세세한 부분까지 공부해보자.
https://kingofbackend.tistory.com/123
https://swk3169.tistory.com/181