Computer Science/[ OS ]

[ OS ] 13. 메모리 관리 전략 - Static Linking vs Dynamic Linking

kim.svadoz 2021. 6. 1. 20:35
반응형

Static Linking vs Dynamic Linking

먼저 Linking(링킹)에 대해 이해를 해보자

링킹은, 프로그램을 빌드하는 과정 (즉 컴파일 과정에서 거치는 단계) 이뤄지는 과정이다.

image-20210516132238958

이 전체를 크게 컴파일 과정이라고 한다.

작은 의미의 컴파일은 Compile 과정이고, 큰 의미의 컴파일은 Compiling + Linking 전 구간을 의미한다.

프로그래머들이 이해하기 쉬운 C/C++로 코드를 짜면 Source.cpp처러 소스파일이 생성된다.

그리고 이를 Build(빌드) 하게 되면 Compiling + Linking 과정을 거친 후 .exe파일을 내보내게 된다.

작은 의미의 컴파일인 Compiling만을 거치게 되면 Object File(목적 파일)Source.obj가 생성되게 되고 실제로 링킹과정까지 거치게 되면 .exe파일로 나오게 되는 것이다.

소스파일은 우리가 이해하기 쉬운 언어들이지 컴퓨터가 이해할 수 있는 단어는 아니다. 따라서 컴퓨터가 실제로 이해하고 실행하기 위해서는 Low Level언어(어셈블리어) , 이진수 파일로 변환해줘야 하는 과정을 거친다.

이렇게 변환하는 것을 Compiling이라 하고 변환해주는 애를 Compiler라고 한다. 이렇게 컴파일 과정 뒤에 생긴 Low Level언어의 파일이 Object File(목적파일)이다.

image-20210516133505278

이 목적파일은 기계어로 작성된 로직과 실행하는데 필요한 부가 정보들(디버깅 정보, Symbol 정보)들로 이루어져 있다. 목적파일(Object File)은 실행파일(temp.exe)과 소스(Source.cpp)의 중간단계 인 것이다.

image-20210516133447440

이렇게 만들어진 Object File들을 링커가 링킹해서 실행파일로 만든다.

그림과 같이 Object File(목적 파일)과 Library Files를 Link(더한게) Executable File(실행파일) 이다.

효율적인 파일 관리를 위해 파일들을 분리해서 관리하는데 링커라는 프로그램은

  1. 여러 소스코드 파일을 하나로 합친다. 즉 Object파일들을 하나로 합친다.
  2. 여기에 Library를 합친다.

의 작업을 통해 실행파일을 만들어 준다.

예를 들어 cout이라는 클래스 라이브러리를 쓰기 때문에 #include <iostream>을 사용할 수 잇는 것처럼 .exe파일들을 하나로 링크하고 있다가, 이 .exe파일에다가 라이브러리를 집어넣어서(합쳐서, 링크해서) 실행파일을 완성하는 것이 바로 linking이다. 정확히는 static linking

Static Linking

Static Linking은 말 그대로 실행파일을 만들 때 라이브러리를 같이 포함시켜 .exe 파일을 만드는 것을 정적 링킹이라고 한다.

  • 장점
    1. 정적 라이브러리를 사용해 컴파일을 하면 링커가 프로그램이 필요로 하는 부분을 라이브러리에서 찾아 실행파일에 바로 복사를 한다.
    2. 실행파일에 다 들어가있기 때문에 라이브러리가 필요가 없다.
    3. 미리 컴파일 되어 있기 때문에 컴파일 시간이 단축된다.
    4. 직접 구현한 코드를 라이브러리화 시켜 기술 유출 방지로 사용 가능하다.
  • 단점
    1. 실행 파일 내에 라이브러리 코드가 저장되기 때문에 메모리를 어마어마하게 잡아먹는다.
    2. 특히, 멀티유저시스템인 LINUX, UNIX OS의 경우 1번은 더욱 심각하다.

예를 들어, 100명의 유저가 LINUX, UNIX 서버에 접속해 동시에 "Hello World"를 출력한다고 가정해보자.

리눅스 에서는 실행파일이 hello 니까 (hello.exe가 아니다.) hello라는 프로그램을 실행시켰는데, 얘가 정적링킹으로 만들어진 실행파일이다.

즉,여기서 출력하는데 사용된 cout이라는 클래스 라이브러리가 정적으로 링킹되어 있다는 것은, hello라는 프로그램에 cout 클래스 라이브러리 코드가 전부 다 들어가있다는 것이다.
즉, hello를 동시에 100명이 실행시키면 메모리에 cout 정보만 100개가 존재하는 것이므로 매우 비 효율 적이다. 그래서 만든 것이 바로 Dynamic Linking이다.

Dynamic Linking

그러면 Dynamic Linking은 무엇일까.

정적 링킹을 쓰니까 메모리에 쓸데 없이 똑같은게 너무 많이 들어있는게 아닌가.

그래서 이 cout과 같이 많이 쓰는 라이브러리는 메모리에 하나만 올리자!

그리고 이 프로그램이 cout을 호출할 때는 메모리에 있는 cout으로 점프해 그쪽으로 간 후에 실행한 다음에 다시 돌아 오게 하자는 것이 Dynamic Lingking이다.

현재 Linux, Unix, 뿐만 아니라 Windows에서도 별다른 옵션을 주지 않으면 Linking은 Dynamic Linking(동적 링킹)을 사용하게 된다.

이 동적 링크 라이브러리를 바로 DLL(Dynamic Link Library)라고 한다. 즉 윈도우에서 동적링킹할 때 사용되는 라이브러리 인데 이 dll파일들은 보통 windows 시스템 디렉토리에 존재한다.

# DLL(Winodws) == Shared Library(Linux, Unix)
Linux나 Unix에서는 DLL이라 부르지 않고 Shared Library라고 부른다.
따라서 .so라고 쓰거나 .sa라고 쓴다.

만약 "Hello World"를 C++ 라이브러리랑 같이 링킹을 해서 실행을 했는데 메모리에 dll파일이 없다. 그러면 실행을 못하니 운영체제가 메모리에 dll파일을 load시켜주는 것이다. 이렇게 메모리에 한번 적재되고 나면 그 다음부터는 적재된 dll파일이 수행되는 것이다.

따라서 동적 라이브러리는 프로그램이 실행될때 링크된다.

# Stub(스텁) 이란?
- 라이브러리가 메모리에 존재하지 않을 때, 라이브러리가 메모리에 상주할 수 있도록 라이브러리 루틴을 적절히 적재하는 방법을 알려주는 작은 코드 조각을 `stub`이라고 한다.
- 스텁은 모든 라이브러리 루틴에 들어 있는데 A라이브러리의 a루틴이 호출되면 stub이 루틴 주소로 대체 되어 그 다음에 그 코드가 한번 더 실수행 될 때는 Dynamic Linking 없이 바로 주소를 참조해 실행할 수 있게 되는 것.
- 런타임시 해당 루틴이 불리면 그 스텁은 자신을 그 루틴이 들어있는 주소값과 바꿔치기 하는 것이다.
- 한 번 스텁이 불리게 되면 스텁이 있었다는 사실은 사라지고 주소가 되어 한몸이 되는 것.
- 단 한개의 원본을 사용하게 해주어 코드가 중복 적재 되지 않아 메모리 절감 효과를 일으킨다.
  • 장점
    1. 메모리 요구사항이 훨씬 적다.
  • 단점
    1. 프로그램 영역에서 라이브러리가 저장되어 있는 주소로 점프를 하게 되어 성능상 약간의 overhead가 발생한다.
    2. Dynamic Linking을 위한 불필요한 코드가 추가된다.(점프 해야 하니까)

성능상에서는 정적 링킹이 좋지만, 메모리 관리 차원에서는 동적 링킹이 좋다.

추가로 동적링킹이 좋은 점은, 우리가 direct X라는 게임 라이브러리를 활용한 게임을 즐긴다고 할 때, 이 게임에 성능이 업그레이드 되면 그 게임을 다시 사는 것이 아니라 Library의 버전만 up하면 되는 것이다. 그냥 업데이트만 해주면 되는 것!

dll 파일은 따로 그대로 저장되기 때문에 원래 코드와 라이브러리가 별도로 있는 것이므로 블랙코드는 그대로 있고, library만 버전업되면 그거에 대한 성능응 그대로 받을 수 있게 되는 것이다.

반응형