나는 두 가지 소스, 즉 프로세스의 메모리 레이아웃에 있는 메모리 매핑 세그먼트에서 공유 메모리 세그먼트의 범위를 찾으려고 했습니다.
~에서https://manybutfinite.com/post/anatomy-of-a-program-in-memory/, 프로세스의 메모리 레이아웃 다이어그램을 찾았습니다.
메모리 매핑된 세그먼트와 힙이 만날 때까지 계속 증가합니까?
아니면 스택 세그먼트의 RLIMIT_STACK과 유사하게 두 세그먼트의 성장에 제한이 있습니까?
Linux 프로그래밍 인터페이스에서
힙 및 스택 증가를 위한 공간을 허용하기 위해 공유 메모리 세그먼트는 가상 주소 0x40000000에서 시작하여 연결됩니다. 매핑 매핑(49장)과 공유 라이브러리(41장 및 42장)도 이 영역에 배치됩니다. (커널 버전과 프로세스의 RLIMIT_STACK 리소스 제한 설정에 따라 공유 메모리 맵과 메모리 세그먼트의 기본 배치에 약간의 차이가 있습니다.) 주소 0x40000000은 커널 상수 TASK_UNMAPPED_BASE로 정의됩니다.
공유 메모리 세그먼트가 TASK_UNMAPPED_BASE에서 시작하여 위쪽으로 증가합니까?
위 그림은 공유 메모리 세그먼트가 아래쪽으로 증가하는 것을 보여주므로 위쪽으로 성장합니까, 아니면 아래쪽으로 성장합니까?
감사해요.
답변1
mmap
세그먼트 및 힙 세그먼트 에는 일부 제한 사항이 적용됩니다 . RLIMIT_AS
사용 가능한 총 주소 공간을 결정합니다. 여기에는 프로그램이 만들 수 있는 모든 메모리 할당이 포함됩니다. RLIMIT_DATA
데이터 세그먼트의 최대 크기를 결정합니다.
커널은 이러한 제한에 대해 스택 확장 mmap
및 brk
(힙 할당)을 확인합니다. 또한 충돌 가능성이 있는 세그먼트에 대한 할당을 확인하므로 세그먼트가 서로 덮어쓰지 않게 됩니다(예를 들어 참조).힙 할당에 대해 수행되는 검사brk
). 할당이 불가능하면 프로그램에 적절하게 "알려집니다". C 라이브러리는 오류를 반환 ENOMEM
하고 스택을 확장할 수 없으면 brk
커널은 다음과 같이 프로그램을 종료합니다.SIGSEGV
공유 메모리 세그먼트(엄격히 말하면 커널 관점에서 가상 메모리 영역)가 커지는 방식은 메모리 레이아웃에 따라 달라지며, 이는 프로세스마다 매우 다를 수 있습니다. 대부분의 아키텍처에서 "전통적인" 메모리 매핑은 TASK_UNMAPPED_BASE
; 비전통적인 메모리 매핑은 하향식 할당을 초래합니다. 바라보다arch_pick_mmap_layout()
그리고mmap_is_legacy()
x86 아키텍처를 예로 들어 보겠습니다. setarch
' 플래그를 사용하여 이전 메모리 맵으로 전환 할 수 있습니다 -L
(아래 예 참조).
실제로 /proc/$$/maps
로드된 공유 라이브러리의 주소(있는 경우)와 로드된 순서를 보고 검사하여 세그먼트가 어떻게 증가하는지 이해할 수 있습니다. 동적 링커는 항상 먼저 로드됩니다. 해당 주소가 다른 라이브러리보다 낮으면 할당은 상향식이고, 그렇지 않으면 하향식입니다. 64비트 x86 시스템의 출력을 비교하십시오 cat /proc/self/maps
.setarch x86_64 -L cat /proc/self/maps