프로그램이 CPU에서 실행되기 위해서는 메모리로 가져와야 하고, 프로세스의 컨텍스트 안에 배치되어야 한다.
컴파일러에 의해서 소스 코드가 기계어로 바뀌는 즉 컴파일되는 작업이다.
링커에 의해서 여러 개의 오브젝트 파일(main.c)들과 여러 라이브러리들이 하나의 실행 파일(main)로 결합되는 작업이다.
== 실제 주소 할당)한다.동적 라이브러리 링크 방식
현대 시스템은 프로그램이 로드될 때 라이브러리를 동적으로 연결하는 동적 라이브러리 링크 방식을 채택한다. 동적 라이브러리 링크 방식은 바로 사용하지 않는 라이브러리를 미리 링크하지 않고, 사용 시 링크해 메모리와 디스크 공간을 절약할 수 있다.
커널 내부 로더에 의해서 프로그램이 메모리에 적재되는 작업이다.
/main 명령어나 GUI(더블클릭)이 수행되면 다음과 같은 작업이 일어난다.fork(), exec() 시스템 콜고 로더를 통해서만 프로세스를 적재할 수 있을까?
특수한 경우 커널 개발자가 직접 메모리에 적재할 수 있지만 보통 로더에 의해서 적재된다.
링커와 로더의 차이!
역할의 차이로는 여러 오브젝트 파일과 라이브러리를 결합해 하나의 실행 파일로 만드는 링커와 하나로 결합된 실행 파일을 메모리에 적재해 실행을 준비하는 로더로 구분할 수 있다.
즉, 링커는 컴파일 이후와 실행 전 사이에 수행되고, 로더는 프로그램 실행 시점에 수행된다.
Java는 Java 컴파일러에 의해 소스 코드(Main.java)가 바이트 코드(Main.Class)로 컴파일 된다.
컴파일 된 바이트 코드는 JVM이 실행하는데 인터프리터 방식 또는 JIT 컴파일러에 사용해 네이티브 코드로 변환시켜 실행할 수 있다.
JIT(Just-In-Time)은 Java 메서드가 처음 호출될 때 바이트 코드를 네이티브 머신 언어로 변환해 실행 속도를 높이는 컴파일러다. 변한된 네이티브 머신 언어는 캐싱되어 이후 재호출 시 바이트 코드 해석없이 캐싱된 네이티브 머신 언어로 바로 실행된다.
public class Hello {
public static void main(String[] args) {
for (int i = 0; i < 1000000; i++) {
int result = compute(i);
}
}
public static int compute(int value) {
return value * value;
}
}
compute(0) 호출 시 compute(i) 바이트 코드를 네이티브 머신 언어로 변환시키고 이를 캐싱한다.
이후 compute(1)~compute(999999)는 캐싱된 네이티브 머신 언어를 갖고 바로 실행해 더 빠른 실행 속도를 보여준다.
Python은 CPython, Jython, PyPy등의 다양한 구현체가 있는데 각 구현체 별로 실행 과정이 다르다.
학습하며 정리한 글이기 때문에 혼용된 표현 또는 잘못된 내용이 있을 수 있습니다.
만약, 발견하신 경우 댓글을 통해 알려주신다면 진심으로 감사드립니다.