공유 라이브러리 및 RAM 사용량로드


40

Linux가 공유 라이브러리를 관리하는 방법에 대해 궁금합니다. (실제로 2009 년 256MB RAM에서 실행되는 데비안 기반 배포판 인 Maemo Fremantle에 대해 이야기하고 있습니다).

libQtCore.so.4에 링크되고 심볼 (클래스 및 함수 사용)을 사용하는 두 개의 실행 파일이 있다고 가정합니다. 간단하게하기 위해 aand 라고 부르겠습니다 b. 두 실행 파일이 동일한 라이브러리에 연결되어 있다고 가정합니다.

먼저 우리는 시작 a합니다. 라이브러리를로드해야합니다. 전체적으로로드되거나 필요한 부분에서만 메모리에로드됩니까 (각 클래스를 사용하지 않으므로 사용 된 클래스와 관련된 코드 만로드되고 있습니까)?

그런 다음 시작 b합니다. 우리 a는 여전히 실행되고 있다고 가정합니다 . blibQtCore.so.4에 링크하고 사용하는 클래스 중 일부는 a사용하지만 일부는 사용하지 않습니다 a. 라이브러리가 이중으로로드 됩니까 (에 a대해 별도로 또는 별도로 b)? 또는 RAM에 이미있는 동일한 객체를 사용합니까? 경우 b사용하는 새로운 기호와 a이미 실행중인 공유 라이브러리에 의해 RAM을 사용하지 않습니다 증가? (또는 그 차이는 중요하지 않습니다)

답변:


53

참고 : 컴퓨터에 메모리 매핑 장치 (MMU)가 있다고 가정하겠습니다. MMU가 필요없는 Linux 버전 (µClinux)이 있으며이 답변은 해당되지 않습니다.

MMU 란 무엇입니까? 프로세서 및 / 또는 메모리 컨트롤러의 일부인 하드웨어 입니다. 공유 라이브러리 연결을 이해한다고해서 MMU의 작동 방식을 정확히 이해할 필요는 없습니다. 단지 MMU를 사용하면 논리적 메모리 주소 (프로그램에서 사용하는 주소)와 물리적 메모리 주소 사이에 차이가있을 수 있습니다메모리 주소 (실제로 메모리 버스에있는 주소). 메모리는 Linux에서 일반적으로 4K 크기의 페이지로 나뉩니다. 4k 페이지의 경우 논리 주소 0–4095는 페이지 0, 논리 주소 4096–8191은 페이지 1 등입니다. MMU는이를 RAM의 실제 페이지에 매핑하고 각 논리 페이지는 일반적으로 0 또는 1 개의 실제 페이지에 매핑 할 수 있습니다. 지정된 실제 페이지는 여러 논리 페이지에 해당 할 수 있습니다 (메모리가 공유되는 방식입니다. 여러 논리 페이지는 동일한 실제 페이지에 해당). 이것은 OS에 관계없이 적용됩니다. 하드웨어에 대한 설명입니다.

프로세스 전환시 커널은 MMU 페이지 매핑을 변경하여 각 프로세스마다 고유 한 공간을 갖습니다. 프로세스 (1000)의 주소 (4096)는 프로세스 (1001)의 주소 (4096)와 완전히 다를 수있다 (그리고 일반적으로).

주소를 볼 때마다 논리 주소입니다. 사용자 공간 프로그램은 실제 주소를 거의 다루지 않습니다.

이제 라이브러리를 빌드하는 여러 가지 방법이 있습니다. 프로그램 foo()이 라이브러리 에서 함수 를 호출한다고 가정 해 봅시다 . CPU는 심볼이나 함수 호출에 대해 전혀 알지 못합니다. 논리적 주소로 이동하여 찾은 코드를 실행하는 방법 만 알고 있습니다. 이를 수행 할 수있는 몇 가지 방법이 있습니다 (라이브러리가 자체 글로벌 데이터 등에 액세스 할 때도 유사한 사항이 적용됨).

  1. 논리 주소를 하드 코딩하여 호출 할 수 있습니다. 이를 위해서는 라이브러리가 항상 동일한 논리 주소로로드되어야합니다. 두 라이브러리에 동일한 주소가 필요한 경우 동적 연결이 실패하고 프로그램을 시작할 수 없습니다. 라이브러리에는 다른 라이브러리가 필요할 수 있으므로 기본적으로 시스템의 모든 라이브러리에는 고유 한 논리 주소가 있어야합니다. 그래도 작동하면 매우 빠릅니다. (이것은 a.out이 일을 한 방식이며 사전 연결이 수행하는 설정의 종류입니다.)
  2. 가짜 논리 주소를 하드 코딩하고 라이브러리를로드 할 때 동적 링커에게 올바른 주소를 편집하도록 지시 할 수 있습니다. 라이브러리를로드 할 때 상당한 시간이 걸리지 만 그 후에는 매우 빠릅니다.
  3. 간접 계층을 추가 할 수 있습니다. CPU 레지스터 를 사용 하여 라이브러리가로드 된 논리 주소를 보유한 다음 해당 레지스터의 오프셋으로 모든 것에 액세스하십시오. 이것은 각 액세스에 대한 성능 비용을 부과합니다.

적어도 범용 시스템에서는 더 이상 # 1을 사용하는 사람이 거의 없습니다. 32 비트 시스템에서는 이러한 고유 한 논리적 주소 목록을 유지하는 것이 불가능하며 (충분할 수는 없음) 64 비트 시스템에서는 관리상의 악몽이 있습니다. 그러나 사전 연결은 시스템별로 수행합니다.

# 2 사용 여부는 라이브러리가 GCC -fPIC(위치 독립적 코드) 옵션 으로 빌드되었는지 여부에 따라 다릅니다 . # 2는없고, # 3은 있습니다. 일반적으로 라이브러리는로 빌드 -fPIC되므로 # 3이 발생합니다.

자세한 내용은 Ulrich Drepper의 공유 라이브러리 작성 방법 (PDF)을 참조하십시오 .

따라서 마지막으로 귀하의 질문에 대답 할 수 있습니다.

  1. 라이브러리가 내장되어있는 경우 -fPIC (거의 확실해야한다로), 페이지의 대부분은 모든 프로세스에 대해 정확히로드합니다 것을 동일합니다. 귀하의 프로세스 a와는 b물론 다른 논리 주소의 라이브러리를로드 할 수 있지만, 사람들은 동일한 물리적 페이지를 가리 킵니다 : 메모리가 공유됩니다. 또한 RAM의 데이터는 디스크의 데이터와 정확히 일치하므로 페이지 결함 핸들러가 필요할 때만로드 할 수 있습니다.
  2. 라이브러리가로 구축 되지 않은 경우 -fPIC대부분의 라이브러리 페이지에서 링크 편집이 필요하고 다를 수 있습니다. 따라서 서로 다른 데이터를 포함하므로 별도의 실제 페이지 여야합니다. 그것은 그들이 공유되지 않음을 의미합니다. 페이지가 디스크의 내용과 일치하지 않으므로 전체 라이브러리가로드 되어도 놀라지 않을 것입니다. 물론 스왑 파일에서 디스크로 스왑 아웃 될 수 있습니다.

pmap도구를 사용하거나에서 다양한 파일을 확인하여 직접 확인할 수 있습니다 /proc. 예를 들어, 여기 pmap -x에 새로 생성 된 두 개의 서로 다른 (부분) 출력이 bc있습니다. pmap으로 표시되는 주소는 일반적인 논리 주소입니다.

pmap -x 14739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f81803ac000     244     176       0 r-x-- libreadline.so.6.2
00007f81803e9000    2048       0       0 ----- libreadline.so.6.2
00007f81805e9000       8       8       8 r---- libreadline.so.6.2
00007f81805eb000      24      24      24 rw--- libreadline.so.6.2


pmap -x 17739
Address           Kbytes     RSS   Dirty Mode  Mapping
00007f784dc77000     244     176       0 r-x-- libreadline.so.6.2
00007f784dcb4000    2048       0       0 ----- libreadline.so.6.2
00007f784deb4000       8       8       8 r---- libreadline.so.6.2
00007f784deb6000      24      24      24 rw--- libreadline.so.6.2

라이브러리가 여러 부분으로로드되어 pmap -x있고 각각에 대한 세부 정보를 제공함을 알 수 있습니다. 두 프로세스간에 논리적 주소가 다르다는 것을 알 수 있습니다. 동일한 프로그램이 실행되고 컴퓨터가 일반적으로 그렇게 예측 가능하기 때문에 동일 할 것으로 예상되지만 의도적으로 임의 하는 주소 공간 레이아웃 임의 화 라는 보안 기능이 있습니다.

전체 라이브러리 세그먼트가로드되지 않은 크기 (KB) 및 상주 크기 (RSS)의 차이에서 볼 수 있습니다. 마지막으로 더 큰 매핑의 경우 dirty는 0이며 이는 디스크의 내용과 정확히 일치 함을 의미합니다.

를 사용하여 다시 실행할 수 있으며 pmap -XX실행중인 커널 버전에 따라 -XX 출력이 커널 버전에 따라 다르므로 첫 번째 매핑 Shared_Clean의 176이 RSS. Shared메모리는 실제 페이지가 여러 프로세스간에 공유되고 RSS와 일치하기 때문에 메모리에있는 모든 라이브러리가 공유됨을 의미합니다 (공유와 개인에 대한 자세한 설명은 아래 참조).

pmap -XX 17739
         Address Perm   Offset Device   Inode  Size  Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked                   VmFlagsMapping
    7f784dc77000 r-xp 00000000  fd:00 1837043   244  176  19          176            0             0             0        176         0             0    0              4           4      0       rd ex mr mw me sd  libreadline.so.6.2
    7f784dcb4000 ---p 0003d000  fd:00 1837043  2048    0   0            0            0             0             0          0         0             0    0              4           4      0             mr mw me sd  libreadline.so.6.2
    7f784deb4000 r--p 0003d000  fd:00 1837043     8    8   8            0            0             0             8          8         8             0    0              4           4      0       rd mr mw me ac sd  libreadline.so.6.2
    7f784deb6000 rw-p 0003f000  fd:00 1837043    24   24  24            0            0             0            24         24        24             0    0              4           4      0    rd wr mr mw me ac sd  libreadline.so.6.2


또한보십시오


그것은 사전 연결이 더 이상 사용되지 않는다는 것을 의미합니다 (그리고 -fPIC몇 시간 전에 사용법이 완전히 바뀌 었습니까)?
Hauke ​​Laging

@crisron 수정 해 주셔서 감사합니다. 참고로, Markdown은 귀하를 위해 계산 1. 합니다. 반복 된 결과물 이 정확했습니다. 또한 "시작 주소"는 기술 용어로, "논리적"을 중간에 배치함으로써 혼란을 야기했을 가능성이 있습니다. 나는 전문 용어를 없애기 위해 그것을 바꿨다. 또한 페이지는 해당 주소와 동일하므로 AFAIK는 해당 주소가 다른 페이지 일 수 없습니다. 주문을 바꾸어 다시 시도했지만 더 명확합니다.
derobert

젠장, 이제 대답입니다!
Evan Carroll
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.