static / dynamic library

yaja·2022년 2월 1일
0
post-thumbnail

SPM으로 라이브러리를 추가하던 도중 궁금한 점이 생겼다.

Dynamic 키워드가 붙은 라이브러리들이 눈에 들어왔다.

dynamic이 붙은 건 뭐고, dynamic이 붙지 않은 건 뭐지? 궁금증이 생겨서 정리해보려고 한다.

Static Library

위의 캡쳐에서 Dynamic 키워드가 붙지 않은 라이브러리가 static library다.

static library는 아카이빙된 object file(.o 확장자)의 모음으로, .a 확장자 형태의 라이브러리이다. (OS에 따라 다름. macOS에 한정)

static library의 특징에 알아보기에 앞서, 소스 코드를 컴파일 후 생겨나는 파일인 object file에 대해 먼저 알아보겠다.

우리가 작성한 소스 코드를 컴파일하게 되면 object files라는 생성되는데, object file은 Mach-O 형식의 바이너리 데이터로 다음과 같은 내용들을 포함한다.

  • Header - 파일이 동작하는 아키텍처에 대한 정보 명시
  • Load Commands - 파일의 논리적인 흐름에 대한 정보 명시
  • Raw Segment Data - raw code와 data

즉, object file은 기계어로 작성된 로직과 실행하는 데에 필요한 부가적인 정보들로 이루어져 있다고 생각하면 된다.

  • +) Mach-O

    Mach Object file format의 줄임말이며, Mach는 Carnegie Mellon University에서 개발된 커널을 의미한다.

    macOS, iOS, iPadOS, tvOS, watchOS에 사용되는 Apple의 XNU가 이러한 Mach를 기반으로 한다. (XNU : Apple에서 만든 OS 커널.) Mach-O는 OS-X의 native excutable format이고, shipping code에 선호되는 format 이다.

우리는 어떠한 언어(예를 들어 swift, java 등)로 코드를 작성할 때, 순수하게 해당 언어로 작성된 코드 뿐만 아니라 필요에 따라 라이브러리를 import 하여 사용한다.

(나의 경우에 RxSwift라는 라이브러리를 적용하려고 했던 것)

혹은 코드가 많아지면 하나의 파일을 여러가지 파일로 나누고, 목적에 맞는 코드끼리 모아 라이브러리를 만들기도 한다.

이러한 라이브러리를 앱 내에서 사용하기 위해서는 라이브러리(object file들의 모음)와 내가 작성한 소스 코드(위에서 언급했듯 컴파일 후 생성된 object file)를 병합하는 과정인 Link 작업이 필요하다.

Link 작업의 시점과 라이브러리를 reference 하는지, 실행 파일에 포함하는지 여부에 따라 static한 라이브러리인지, dynamic한 라이브러리인지가 결정된다.

Static link

위의 그림은 프로젝트를 빌드하는 과정을 나타낸다.

Source Code 영역은 programming language text의 모음이고(우리가 코딩 하면서 소스 코드를 적은 것), 앞서 언급했듯 Compiling 과정을 통해 Object code file이 생성된다. 이러한 모든 Object code file은 linker를 통해 연결되고 결과적으로 여러 개의 object들이 연결되면서 하나의 실행 파일(excutable)이 생성된다.

link 과정은 다음과 같다.
linker는 컴파일을 통해 생성된 object file들을 하나로 합치고, 여기에 library를 합친다. 먼저 object file에 있는 동일한 섹션들이 하나의 chuck가 되고 이렇게 하나의 chuck가 된 파일은 라이브러리와 합쳐지는 것이다. 이러한 과정을 static linking이라고 부른다.
중요한 것은 라이브러리가 하나의 실행 파일에 통째로 합쳐진다는 것이다.

다음은 iOS에서 어플리케이션이 static library를 사용하는 구조이다.

계속 말했던 것 처럼, source code와 static library는 static linker를 통해 하나의 어플리케이션 파일(executable file)로 병합되고 이는 라이브러리에 포함된 코드 전부를 앱 내에 포함시킨다. 이렇게 만들어진 어플리케이션 파일은 앱이 실행될 때 앱의 주소 공간에 로드되게 된다.

여기까지 static library / static linking에 대해 알아보았다.

그렇다면 dynamic한 library는 무엇이고 왜 나오게 되었는가?

static link에서 linker는 executable을 만들 때, source code 뿐만 아니라 static library 자체를 executable 파일에 포함시킨다고 했다.

이 말은 곧 우리가 많은 static library를 사용하게 되면 executable 의 사이즈가 증가한다는 의미이며, 이는 곧 앱의 lauch time을 느리게 만들고 많은 메모리를 사용하게 한다는 의미이기도 하다.

또한 static library는 linker를 통해 링킹하는 시점의 라이브러리를 실행 파일에 병합하기 때문에 라이브러리의 업데이트에 유연하지 않다. 라이브러리의 성능이 업데이트되면 새로운 버전의 라이브러리와 앱의 oject file가 다시 link 되어야만(즉, 다시 빌드과정을 거쳐야만) 업데이트된 사항이 앱에 반영될 수 있다는 소리이다.

이러한 static library의 특징 때문에 dynamic library가 나오게 된다.

Dynamic Library

static library는 source code와 합쳐져 실행 파일에 포함되는 반면 dynamic library는 실행 파일에 라이브러리 코드가 포함되지 않는다. 따라서 앱의 실행 파일은 동일한 라이브러리를 static하게 만들었을 때와 비교했을 때 더 작은 크기이다. 라이브러리를 앱 실행 파일에 통째로 copy하는 대신 dynamic library에 대한 reference만 executable file에 포함하며, 라이브러리는 앱이 실행될 때 앱 주소 공간에 로드된다.

static library를 사용하게 되면, 해당 라이브러리를 사용하는 각각의 프로그램은 각각의 실행 파일마다 동일한 static library를 포함한다. 이는 곧 중복되는 메모리가 존재한다는 의미이다.

반면 dynamic library는 실행 파일에 라이브러리 코드를 포함하는 게 아니라 주소를 포함하기 때문에, 각각의 프로그램들은 메모리를 공유하게 되므로(단 한 개의 원본 라이브러리를 참조) 중복된 메모리가 존재하지 않게 된다. 이런 의미에서 dynamic library는 shared library라고도 불린다.

다만 dynamic library는 주소 공간에 라이브러리를 Load 하는 데에 걸리는 시간이 필요하기 때문에, pre-main time이 다소 길어질 수 있고 이는 결국 launch time의 증가로 이어질 수도 있다.

참고로 dynamic library를 사용하여 개발하는 것은 App store용으로 사용할 수 없다고 한다. App store 에 배포되기 위해서는 애플의 심사를 거쳐야하는데, dynamic library를 사용하는 것은 심사 후에 앱이 수정될 가능성을 갖고 있기 때문이고 애플은 이를 허용하지 않기 때문이다.

궁금증

  1. slow launch time

static library의 large executable은 slow launch time을 만든다.

또한 dynamic library를 사용할 경우 라이브러리를 로드하는 데에 걸리는 시간이 많이 들고, 따라서 pre-main time이 증가하고 이는 slow launch time로 이어질 수 있다.

둘 다 launch time을 증가시킬 가능성을 내포하고 있다면 어떤 게 더 빠른 launch time을 보장하는가?

일반적으로 성능 면에서는 static library가 우세하다고 한다. static library는 앱 실행 파일에 라이브러리가 직접 복사되어 있으므로 라이브러리를 가져오는 속도가 빠르기 때문이다. 그러나 dynamic library는 라이브러리의 참조만을 앱 실행 파일에 포함하고 있기 때문에 라이브러리를 호출하는 속도가 다소 lazy 할 수 있다고 한다.

  1. dynamic library의 loading과 linking
  • dynamic library는 메모리를 load 하는 데에 시간이 걸리고, 이로 인해 launch time이 증가할 수 있다

  • dynamic library는 runtime 시점에 라이브러리와 Link 된다

🤦‍♀️ : load? Link? 메모리에 load 되는 건 뭐고, runtime 시점에 link 되는 건 뭐지? 그래서 대체 언제 어떻게 라이브러리를 가져온다는 거지? runtime 시점에 link 된다면서, launch time이 증가하는 건 뭔 소리세요?

이것 저것 찾아보고 내가 이해한 바로 정리해보면, dynamic library의 reference를 가지고 있는 프로그램을 실행하면 내부적으로 dynamic loader 라는 프로그램이 동작하여 다음과 같은 동작을 실행한다.

  1. dynamic link에 필요한 공유 라이브러리를 찾아서 메모리에 로드
  2. entry function을 찾아서 호출 (entry function이 호출 되기까지 걸리는 시간을 pre-main time이라고 함.)
  3. 프로그램 실행.

이렇게 다이나믹 로더가 위와 같은 동작을 실행하고, 런타임 시점에 라이브러리가 필요할 때마다 메모리에 적재되어있는 라이브러리의 API를 호출하여 사용하는 듯 하다.

+) 위의 내용은 종속 라이브러리에 관한 내용(dependent library)이고, 앱이 실행 될 때 동적 라이브러리를 실행할 필요가 없는 경우에는 런타임 시점에 동적 라이브러리를 로드하도록 할 수 있다. (runtime loaded library) 이렇게 되면 launch time을 줄일 수 있게 된다.

runtime 시점에 link 한다면서, launch time이 증가하는 게 이해가 안됐는데 상충되는 개념이 아니라 동적 라이브러리가 두 가지로 나뉠 수 있는 것이다.

참고

잘못된 점이 있다면 언제든지 알려주시면 감사하겠습니다

profile
나의 언어로 설명할 수 있을 때까지 😎

0개의 댓글