Linux가 공유 라이브러리를 관리하는 방법에 대해 궁금합니다. (실제로 2009 년 256MB RAM에서 실행되는 데비안 기반 배포판 인 Maemo Fremantle에 대해 이야기하고 있습니다).
libQtCore.so.4에 링크되고 심볼 (클래스 및 함수 사용)을 사용하는 두 개의 실행 파일이 있다고 가정합니다. 간단하게하기 위해 a
and 라고 부르겠습니다 b
. 두 실행 파일이 동일한 라이브러리에 연결되어 있다고 가정합니다.
먼저 우리는 시작 a
합니다. 라이브러리를로드해야합니다. 전체적으로로드되거나 필요한 부분에서만 메모리에로드됩니까 (각 클래스를 사용하지 않으므로 사용 된 클래스와 관련된 코드 만로드되고 있습니까)?
그런 다음 시작 b
합니다. 우리 a
는 여전히 실행되고 있다고 가정합니다 . b
libQtCore.so.4에 링크하고 사용하는 클래스 중 일부는 a
사용하지만 일부는 사용하지 않습니다 a
. 라이브러리가 이중으로로드 됩니까 (에 a
대해 별도로 또는 별도로 b
)? 또는 RAM에 이미있는 동일한 객체를 사용합니까? 경우 b
사용하는 새로운 기호와 a
이미 실행중인 공유 라이브러리에 의해 RAM을 사용하지 않습니다 증가? (또는 그 차이는 중요하지 않습니다)
답변
참고 : 컴퓨터에 메모리 매핑 장치 (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는 심볼이나 함수 호출에 대해 전혀 알지 못합니다. 논리적 주소로 이동하여 찾은 코드를 실행하는 방법 만 알고 있습니다. 이를 수행 할 수있는 몇 가지 방법이 있습니다 (라이브러리가 자체 글로벌 데이터 등에 액세스 할 때도 유사한 사항이 적용됨).
- 논리 주소를 하드 코딩하여 호출 할 수 있습니다. 이를 위해서는 라이브러리가 항상 동일한 논리 주소로로드되어야합니다. 두 라이브러리에 동일한 주소가 필요한 경우 동적 연결이 실패하고 프로그램을 시작할 수 없습니다. 라이브러리에는 다른 라이브러리가 필요할 수 있으므로 기본적으로 시스템의 모든 라이브러리에는 고유 한 논리 주소가 있어야합니다. 그래도 작동하면 매우 빠릅니다. (이것은 a.out이 일을 한 방식이며 사전 연결이 수행하는 설정의 종류입니다.)
- 가짜 논리 주소를 하드 코딩하고 라이브러리를로드 할 때 동적 링커에게 올바른 주소를 편집하도록 지시 할 수 있습니다. 라이브러리를로드 할 때 상당한 시간이 걸리지 만 그 후에는 매우 빠릅니다.
- 간접 계층을 추가 할 수 있습니다. CPU 레지스터 를 사용 하여 라이브러리가로드 된 논리 주소를 보유한 다음 해당 레지스터의 오프셋으로 모든 것에 액세스하십시오. 이것은 각 액세스에 대한 성능 비용을 부과합니다.
적어도 범용 시스템에서는 더 이상 # 1을 사용하는 사람이 거의 없습니다. 32 비트 시스템에서는 이러한 고유 한 논리적 주소 목록을 유지하는 것이 불가능하며 (충분할 수는 없음) 64 비트 시스템에서는 관리상의 악몽이 있습니다. 그러나 사전 연결은 시스템별로 수행합니다.
# 2 사용 여부는 라이브러리가 GCC -fPIC
(위치 독립적 코드) 옵션 으로 빌드되었는지 여부에 따라 다릅니다 . # 2는없고, # 3은 있습니다. 일반적으로 라이브러리는로 빌드 -fPIC
되므로 # 3이 발생합니다.
자세한 내용은 Ulrich Drepper의 공유 라이브러리 작성 방법 (PDF)을 참조하십시오 .
따라서 마지막으로 귀하의 질문에 대답 할 수 있습니다.
- 라이브러리가 내장되어있는 경우 에
-fPIC
(거의 확실해야한다로), 페이지의 대부분은 모든 프로세스에 대해 정확히로드합니다 것을 동일합니다. 귀하의 프로세스a
와는b
물론 다른 논리 주소의 라이브러리를로드 할 수 있지만, 사람들은 동일한 물리적 페이지를 가리 킵니다 : 메모리가 공유됩니다. 또한 RAM의 데이터는 디스크의 데이터와 정확히 일치하므로 페이지 결함 핸들러가 필요할 때만로드 할 수 있습니다. - 라이브러리가로 구축 되지 않은 경우
-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
또한보십시오
- 전체 clean / dirty 공유 / 비공개 항목 에 대한 설명은 / proc / pid / smaps에서 프로세스 메모리 사용량에 대한 정보를 가져옵니다 .