[CS 스터디] 컴파일러 vs 인터프리터

Yewon Jeong·2023년 6월 3일
0

CS 스터디

목록 보기
19/19

고급 언어와 저급 언어

고급->저급으로 갈수록 기계가 이해하기 쉬워짐.

컴파일러 vs 인터프리터

컴파일러

  • 코드 실행 전, 컴파일 타임에 소스 코드 전체를 한번에 기계어로 변환 후 실행
  • 실행 파일 생성
  • 컴파일 단계와 실행 단계가 분리
  • 실행시에는 컴파일 과정을 거치지 않고 실행만 하면 되므로 코드 실행 속도가 빠르다
  • 단, 프로젝트의 규모가 클 경우 컴파일 시간이 오래 걸릴 수 있다는 단점이 있다.
  • C, C++, C#, JAVA 등

인터프리터

  • 코드가 실행 단계인 런타임에 코드 한 줄씩 중간 코드인 바이트코드로 변환 후 실행
  • 실행 파일 생성 X
  • 컴파일 하는 과정이 없기 때문에 컴파일 하는 시간은 소요되지 않으나, 인터프리터 언어는 실행파일을 별도로 생성하지 않기 때문에 실행시마다 인터프리트 과정이 반복 수행되어 실행 속도가 느리다는 단점
  • Python, Javascript, Ruby 등

C언어 컴파일 과정

빌드(Build)

컴퓨터에서 이해할 수 있는, 즉 실행 가능한 파일로 만드는 과정.
우리가 만든 소스코드를 '빌드'하면 실행 파일을 얻는다.(.exe)

clang이라는 컴파일러를 호출해서 C 소스 코드를 오브젝트 코드(물리적인 기계가 바로 읽어낼 수 있는 코드)로 컴파일.컴파일의 전체 과정은 네 단계로 나누어 볼 수 있다.

  1. 전처리(Precompile) : # 으로 시작되는 C 소스 코드는 전처리기에게 실질적인 컴파일이 이루어지기 전에 무언가를 실행하라고 알려줌. 예를 들어, #include는 전처리기에게 다른 파일의 내용을 포함시키라고 알려준다.
  2. 컴파일(Compile):C코드를 어셈블리어라는 저수준 프로그래밍 언어로 컴파일
  3. 어셈블(Assemble):어셈블리 코드를 오브젝트 코드로 변환
  4. 링크(Link):여러개의 다른 오브젝트 코드 파일을 실행가능한 하나의 오브젝트 코드 파일로 합침.

자바스크립트 실행 과정


  1. 파싱 (Parsing)
    1-1) 토큰화: 코드를 작은 단위인 토큰(Token)으로 분활. 토큰은 예약어, 식별자,연산자,숫자,문자열 등과 같은 코드의 의미 있는 부분을 말함.(소스코드를 의미있는 단위로 나누는 과정)
    1-2) 구문 분석: 토큰들을 조합하여 문법 규칙에 따라 코드의 구조를 분석. 이를 통해 코드의 구성 요소와 관계를 이해하고, 문법적으로 유효하진 검사

  2. 추상 구문 트리 (Abstract Syntax Tree, AST) 생성:파싱된 코드는 추상 구문 트리라고 불리는 트리 형태의 자료구조로 변환. 추상 구문 트리는 코드의 구조를 계층적으로 표현하여 코드 실행에 필요한 정보를 담고있음. 각 노드(소스 코드의 항목(item)에 해당)는 토큰이나 표현식, 문장 등을 나타내며, 노드들 간의 관계를 통해 코드의 의미를 전달

  3. 바이트 코드 생성: 추상 구문 트리를 기반으로 인터프리터는 중간 표현 형태인 바이트 코드(Bytecode)를 생성.바이트 코드(가상 머신(자바스크립트 엔진)이 읽는 코드)는 자바스크립트 엔진이 이해하고 실행할 수 있는 낮은 수준의 명령어로 구성된 형태

  4. 실행: 생성된 바이트 코드(중간언어)는 인터프리터에 의해 한 줄씩 실행됩니다. 각 바이트 코드 명령은 스택 기반 가상 머신(자바스크립트 엔진)(Virtual Machine)에서 실행되며, 필요한 연산이 수행되거나 변수의 값이 변경될 수 있음.
    *중간언어 : 고급언어와 기계어 사이의 언어를 뜻하는데 하드웨어가 아닌 가상 컴퓨터에서 돌아가는 실행 프로글매을 위한 이진 표현법.

*JIT(Just-In-Time) 컴파일러

모던 자바스크립트 컴파일러는 거의 런타임 내에서 빠르게 컴파일(JITC, Just-In-Time Compilation)을 수행한다.
결론적으로, V8은 JIT 컴파일 방식을 통해 바이트코드, 최적화 기계어를 통해 규모가 큰 js 파일을 고성능으로 돌릴 수 있게 되었다.(반복적으로 실행되는 코드에 대해 큰 성능 향상)

  • 동작과정
    • 인터프리터 실행: 프로그램이 실행되면 인터프리터가 코드를 한 줄씩 해석하고 실행.
    • 동적 프로파일링: 인터프리터는 실행 중인 코드의 실행 통계 정보를 수집. 이 정보에는 코드의 자주 실행되는 부분, 데이터 타입, 루프 등의 정보가 포함될 수 있음.
    • 컴파일 대상 식별: 동적 프로파일링을 통해 인터프리터는 실행 속도를 향상시키기 위해 컴파일 대상으로 판단되는 코드를 식별. 일반적으로 자주 실행되는 루프나 복잡한 계산 등이 컴파일 대상이 될 수 있음.
    • JIT 컴파일: JIT 컴파일러는 컴파일 대상 코드를 중간 표현 형태에서 기계어로 변환. 이때 최적화 기법을 적용하여 실행 성능을 향상시킴. 컴파일된 코드는 메모리에 캐시되거나 바로 실행.
    • 기계어 실행: JIT 컴파일된 코드는 인터프리터가 유지하는 중간 표현 형태의 코드 대신 직접 실행. 이로써 JIT 컴파일러는 인터프리터에 비해 더 빠른 실행 속도를 제공할 수 있음.

파이썬 인터프리터

  • Cpython : 프로그래밍 언어의 공식적인 구현체(파이썬의 표준 인터프리터,c언어로 작성됨.) Python의 고질적인 GIL 문제는 CPython의 GC때문에 존재한다. == CPython 이외에는 GIL없는 경우도 있음
    • cython: 파이썬과 C/C++의 혼합 언어. 파이썬을 c로 변환하여 컴파일된 형태로 실행.
      • python의 경우 구조적으로 멀티프로세스를 실행하는데 어려움이 있다.
      • GIL(Global Interpreter Lock)=> 한 번에 하나의 스레드 만이 파이썬바이트 코드를 실행할 수 있음. => 이 단점을 극복하고자 cython이 등장.
  • Jython : python 코드를 java 바이트코드로 만들어 JVM에서 실행할 수 있도록 한다.Jython은 Global Interpreter Lock (GIL) 문제가 없는 것으로 알려져 있음

+) pypy : 인터프리터가 python으로 작성됨. JIT 컴파일 도입하여 CPython 보다 빠르다.

c,c++ 과 같이 명확하게 구분할 수 있는 언어도 있으나, 현대의 많은 프로그래밍 언어 중에서는 컴파일 언어와 인터프리터 언어간의 경계가 모호한 경우가 많다. 가령 대표적인 인터프리터 언어로 알려진 파이썬도 컴파일을 하지 않는 것은 아니며, Java의 경우 저급 언어가 되는 과정에서 컴파일과 인터프리트를 동시에 수행한다.
즉, 하나의 프로그래밍 언어가 반드시 둘 중 하나의 방식만으로 작동한다고 생각하는 것은 오개념이다.

참고
https://gguguk.github.io/posts/how_to_work_python/
https://velog.io/@seungchan__y/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%8A%94-Compiler-Interpreter-%EC%96%B8%EC%96%B4%EB%8B%A4
https://gyujincho.github.io/2018-06-19/AST-for-JS-devlopers
<도서> 혼자 공부하는 컴퓨터 구조+운영체제

profile
일단 하는 중

0개의 댓글