C에서는 메모리를 할당하고 해제하기 위해 malloc과 free를 직접 사용합니다. 그러나 메모리를 자주 할당하고 해제하면 메모리 조각이 발생하고 시스템 성능이 저하됩니다. malloc을 직접 사용하면 자주 사용됩니다. 할당은 심각한 성능 문제를 일으킬 수 있으므로, PHP는 자체 메모리 풀 ZendMM을 구현하여 glibc의 malloc을 대체하고 빈번한 메모리 할당 및 해제 문제를 해결했습니다.
청크, 페이지, 슬롯의 세 가지 단위로 메모리 작업을 정의합니다. 각 청크의 크기는 2MB이고 각 페이지는 512페이지로 절단되며, 신청 시 각 페이지는 여러 개의 슬롯으로 절단됩니다. 메모리, 애플리케이션의 크기에 따라 다양한 할당 전략이 구현됩니다
거대: 2MB 이상, 시스템 할당을 직접 호출, 여러 청크 할당
대형: 3092B(3/4페이지) 이상, 2044kb(511페이지) 미만의 메모리 적용 ), 여러 페이지 할당
소규모: 요청된 메모리가 3092B 미만인 경우 메모리 풀은 30개의 서로 다른 크기의 메모리(8, 16, 32..., 3072)를 미리 정의했습니다. 메모리를 신청하면 해당 메모리 슬롯을 직접 검색할 수 있으며, 메모리 풀은 대용량 메모리 연결 목록, 청크 연결 목록, 슬롯 내 다양한 크기의 메모리 연결 목록 등 메모리 풀의 주요 정보를 zend_mm_heap 구조를 통해 저장합니다.
대용량 메모리는 실제로 여러 청크에 할당되며 zend_mm_huge_list 구조를 통해 관리됩니다. 대용량 메모리 이들 사이에는 단방향 연결 목록이 형성됩니다.
청크는 시스템에서 메모리를 적용하고 해제하기 위한 메모리 풀의 최소 단위입니다. 청크 간에는 양방향 연결 목록이 형성됩니다. 첫 번째 청크의 주소는 zend_mm_heap->main_chunk에 저장되며, 첫 번째 페이지의 메모리는 포인터 등 청크 자체의 구조체 멤버를 저장하는 데 사용됩니다. 이전 및 다음 청크, 현재 청크의 각 페이지 사용량 등
동일한 크기의 슬롯이 단일 연결 목록을 형성합니다.
메모리 풀의 초기화는 php_module_startup 단계에서 완료됩니다. 초기화 프로세스는 주로 할당을 수행합니다. 힙 구조에서 이 프로세스는 start_memory_manager 프로세스에서 완료됩니다. 다중 스레드 환경인 경우 스레드는 서로 영향을 주지 않습니다. 환경 변수 use_zend_alloc_huge_pages는 Non-threads 안전한 환경에서는 할당된 힙이 AG 매크로인 alloc_globals에 저장됩니다. zend_mm_heap 구조체는 별도로 할당되지 않고 내장되어 있습니다. 청크 구조는 한 페이지를 차지하기 때문에 실제로는 그렇게 큰 메모리를 사용하지 않아서 공간을 최대한 활용하기 위해 여기에 넣어두었습니다
메모리 할당: 1. 엄청난 메모리 할당 2MB를 초과하면 n개의 청크로 정렬되어 할당됩니다. zned_mm_huge_list 구조는 모든 대용량 메모리를 관리합니다. 메모리 정렬 프로세스는 단순히 운영 체제에 따라 완료되는 것이 아니라 적용 후 메모리 풀 자체에서 조정됩니다. 메모리 정렬이 달성되면 직접 조정하고 돌아갈 필요가 없습니다. ZEND_MM_CHUNK_SIZE(2MB)의 정수 배수가 아닌 경우 zendMM은 이 메모리를 해제한 다음 실제 메모리 크기 + ZEND_MM_CHUNK_SIZE에 따라 다시 적용합니다. 추가 블록은 조정에 사용됩니다. 2. 대규모 할당: 요청된 메모리 크기가 3072B(3/4페이지)에서 2044k(511페이지) 사이인 경우 메모리 풀은 청크에서 해당 페이지 수를 검색하여 반환합니다. .large의 응용 단위는 페이지이며 청크에는 free_map과 map이 있습니다. 두 멤버는 페이지 할당 정보를 기록하는 데 사용됩니다.
free_map은 512비트이며 청크에 페이지 할당을 기록하는 데 사용됩니다. , 1로 설정됩니다. 맵은 페이지의 할당 유형과 할당된 페이지 수를 기록하는 데 사용됩니다. 각 페이지는 배열 멤버에 해당하며, 가장 높은 2자리는 페이지의 할당 유형을 기록합니다. 할당할 때 첫 번째 청크부터 순회를 시작하여 해당 청크에 요구 사항을 충족하는 페이지가 있는지 확인하고, 현재 청크에 적합한 페이지가 없으면 다음 청크를 검색합니다. 결국 청크를 다시 할당합니다. 신청할 때 누가 충분한 페이지를 찾았는지 모르겠지만, 청크의 공백을 최대한 채우고 할당된 페이지를 서로 연결하려고 합니다. 중간에 페이지 공백을 피하기 위해 (이후 할당 시 검색 횟수를 줄이기 위해) 1) 첫 번째 청크 그룹(0~63)부터 검사를 시작합니다. 현재 그룹에 사용 가능한 페이지가 있으면 먼저 해당 그룹의 비트를 검사합니다. 현재 페이지, 첫 번째 및 마지막 무료 페이지 위치 찾기, 충분하지 않은 경우 이 페이지를 1(할당됨)로 표시, 다른 그룹 검색, 페이지가 적합하면 직접 사용, 검색을 중단 페이지가 필요한 것보다 큽니다. 이는 사용 가능하지만 최적이 아님을 나타내며 최종적으로 최적의 페이지(페이지 사용을 최대화할 수 있는 페이지)를 비교할 때까지 다른 청크를 계속 검색합니다. 2) 적절한 페이지를 찾은 후, 해당 페이지 정보, 즉 free_map 및 map을 설정한 다음 페이지 주소 3으로 정보를 반환합니다. 소규모 할당:
먼저 해당 사양의 메모리가 할당되었는지 또는 할당되지 않았는지 확인합니다. 다 사용되면 해당 페이지 수에 적용됩니다. 페이지 할당 프로세스는 페이지 할당 후 고정된 크기에 따라 슬롯으로 절단됩니다. . 연결리스트의 선두는 AG(mm_heap)->free_slot
에 저장됩니다.메모리 풀 해제의 세분성은 청크이며 이는 efree를 통해 완료됩니다. 1. 거대 메모리, 대형, 소형 메모리 유형의 해제는 청크의 첫 번째 페이지가 점유되어 있기 때문에 오프셋이 0일 수 없습니다. 청크를 기준으로 구분되므로 청크 유형과 크고 작은 유형을 해제하면 점유된 청크가 해제되고 동시에 AG 연결 목록에서 삭제됩니다. 2. 대용량 메모리 해제: 계산된 오프셋인 경우. 가 0이 아닌 경우 주소가 크거나 작은 메모리임을 의미하며 오프셋에 따라 페이지 번호를 계산합니다. 페이지를 가져온 후 청크->맵에서 페이지의 할당 유형을 가져올 수 있습니다. 지정된 유형의 메모리를 해제합니다. Large는 이를 직접 해제하지 않지만 페이지의 할당 정보를 할당되지 않음으로 설정합니다. 해제 후 청크가 할당되지 않은 것으로 확인되면 해제됩니다. 캐시 번호가 특정 값에 도달하면 새로 추가된 청크는 더 이상 캐시되지 않고 메모리가 반환됩니다. 시스템에서는 캐시된 청크를 할당할 때 너무 많은 메모리를 차지하지 않도록 하세요. chached_chunks에 있으므로 시스템에 적용하지 않고 바로 꺼내서 사용할 수 있습니다. 3. 소형 릴리스, 릴리스된 슬롯을 규칙 슬롯의 사용 가능한 연결 목록에 직접 삽입하면 됩니다. 비교적 간단합니다.
C에서는 메모리를 할당하고 해제하기 위해 malloc과 free를 직접 사용합니다. 그러나 메모리를 자주 할당하고 해제하면 메모리 조각이 발생하고 시스템 성능이 저하됩니다. malloc을 직접 사용하면 자주 사용됩니다. 할당은 심각한 성능 문제를 일으킬 수 있으므로, PHP는 glibc의 malloc을 대체하고 빈번한 메모리 할당 및 해제 문제를 해결하기 위해 자체 메모리 풀 ZendMM을 구현했습니다. 청크, 페이지, 슬롯의 세 가지 세분화된 메모리 작업을 정의합니다. 각 청크의 크기는 2MB이고 각 페이지는 4kB입니다. 하나의 청크는 512페이지로 절단되고 각 페이지는 여러 슬롯으로 절단됩니다. 요청한 크기에 따라 구현
거대: 2MB보다 큼, 시스템 할당을 직접 호출, 여러 청크 할당
대형: 3092B(3/4page)보다 큰 메모리에 적용, 2044kb(511page)보다 작음, 여러 페이지 할당
작음 : 3092B 이하의 메모리를 신청합니다. 메모리 풀은 30가지의 서로 다른 크기(8, 16, 32..., 3072)를 미리 정의했습니다. 메모리 신청 시 해당 메모리에 직접 배포됩니다. 해당 슬롯을 찾습니다. 메모리 풀은 zend_mm_heap 구조를 통해 대용량 메모리 연결 리스트, 청크 연결 리스트, 각 슬롯 크기의 메모리 연결 리스트 등 메모리 풀의 주요 정보를 저장합니다.
대용량 메모리는 실제로 여러 개에 할당됩니다. 그런 다음 zend_mm_huge_list 구조를 통해 관리되는 청크는 큰 메모리 사이에 단방향 연결 목록이 형성됩니다.
청크는 시스템에서 메모리를 적용하고 해제하기 위한 메모리 풀의 최소 세분성입니다. 청크 간에 이중 연결 목록이 형성됩니다. 첫 번째 청크의 주소는 첫 번째 페이지인 zend_mm_heap->main_chunk에 저장됩니다. 메모리는 앞 청크와 뒷 청크의 포인터, 현재 페이지의 사용량과 같은 청크 자체 구조 멤버를 저장하는 데 사용됩니다.
같은 크기의 슬롯이 단일 연결 리스트를 형성합니다
메모리 풀의 초기화는 php_module_startup 단계에서 완료되며, 초기화 프로세스는 주로 힙 구조를 할당합니다. 이 프로세스는 start_memory_manager 프로세스에서 완료됩니다. 다중 스레드 환경인 경우 각 스레드에 대해 메모리 풀이 할당됩니다. 스레드는 서로 영향을 미치지 않습니다. 환경 변수 use_zend_alloc_huge_pages 에 따라 메모리 거대 페이지 활성화 여부가 설정됩니다. 스레드로부터 안전하지 않은 환경에서는 할당된 힙이 AG 매크로인 alloc_globals에 저장됩니다. zend_mm_heap 구조는 별도로 할당되지 않고 청크 구조에 포함되어 있으므로 주의해야 합니다. . 하지만 실제로는 그렇게 큰 메모리를 사용하지 않습니다. 공간을 최대한 활용하기 위해 여기에 넣습니다
메모리 할당: 1. 2MB를 초과하는 대용량 메모리 할당은 할당 시 n개의 청크로 정렬됩니다. 모든 거대한 메모리를 관리하기 위해 zned_mm_huge_list 구조도 할당됩니다. 메모리 정렬 프로세스는 단순히 운영 체제에 의해 완료되는 것이 아니라 적용 후 메모리 풀 자체에 의해 조정됩니다. 메모리에 도달하면 조정이 필요하지 않으며 직접 사용하도록 돌아갑니다. ZEND_MM_CHUNK_SIZE(2MB)의 정수 배수가 아닌 경우 zendMM은 이 메모리 조각을 해제한 다음 실제 메모리 크기 + ZEND_MM_CHUNK_SIZE에 따라 다시 적용합니다. 2. 대용량 할당: 적용되는 메모리 크기가 3072B(3/4페이지)에서 2044k(511페이지) 사이인 경우 메모리 풀은 청크에서 해당 페이지 수를 검색합니다. 큰 응용 프로그램 단위는 페이지이며 free_map과 map 두 멤버는 페이지 할당 정보를 기록하는 데 사용됩니다
free_map은 512비트이며 청크에 페이지 할당을 기록하는 데 사용됩니다. , 1로 설정
맵은 페이지의 할당 유형과 할당된 페이지 수를 기록하는 데 사용되며, 각 페이지는 배열 멤버에 해당하며 가장 높은 2자리는 페이지의 할당 유형을 기록하며, 01은 대형입니다. 10은 작습니다. 할당 시 첫 번째 청크부터 순회를 시작하여 해당 청크에 요구 사항을 충족하는 페이지가 있는지 확인하고, 적합한 경우 다음 청크를 검색합니다. 끝까지 적합하지 않은 경우 청크를 다시 할당합니다. 신청할 때 누가 충분한 페이지를 찾았는지 모르지만 페이지 공백을 피하기 위해 할당된 페이지에 최대한 공백을 메웁니다. (이후 할당 시 검색 횟수를 줄이기 위해) 1) 첫 번째 청크 그룹(0~63)부터 확인을 시작합니다. 현재 그룹에 사용 가능한 페이지가 있으면 먼저 현재 페이지 비트를 찾습니다. 첫 번째와 마지막 무료 페이지의 위치가 충분하지 않으면 이 페이지를 1(할당됨)로 표시하고, 다른 그룹을 검색하고, 페이지가 딱 맞으면 직접 사용하고, 페이지가 다음보다 크면 검색을 중단합니다. need가 크면 사용 가능하지만 최적이 아님을 의미합니다. 최종적으로 비교하여 최적의 청크(페이지 사용을 최대화할 수 있는 청크)를 찾을 때까지 계속해서 다른 청크를 검색합니다. 2) 적절한 페이지를 찾은 후, 해당 페이지 정보를 설정합니다. 즉, free_map 및 map 정보는 페이지 주소를 반환합니다. 3. 작은 할당:
해당 사양의 메모리가 할당되지 않았거나 할당이 된 경우 먼저 확인합니다. 모두 사용되면 해당 페이지 수에 적용됩니다. 페이지 할당 프로세스는 대규모 할당과 일치합니다. 페이지에 적용한 후 고정 크기에 따라 슬롯을 자르고 슬롯을 단일로 연결합니다. 연결 목록, 연결 목록의 선두를 AG(mm_heap)->free_slot
에 저장합니다.메모리 풀 해제의 세분성은 청크이며 efree를 통해 완료됩니다. 1. 거대, 대형, 소형 메모리 유형의 해제는 청크의 첫 번째 페이지가 점유되어 있기 때문에 상대 오프셋이 0일 수 없습니다. Chunk 유형과 Large, Small 유형을 해제할 때 점유된 청크가 해제됨과 동시에 AG 연결 리스트에서 삭제됩니다. 2. 대용량 메모리 해제: 계산된 오프셋인 경우. 가 0이 아닌 경우 주소가 크거나 작은 메모리임을 의미하며 오프셋에 따라 페이지 번호를 계산합니다. 페이지를 가져온 후 청크->맵에서 페이지의 할당 유형을 가져올 수 있습니다. 지정된 유형의 메모리를 해제합니다. Large는 이를 직접 해제하지 않지만 페이지의 할당 정보를 할당되지 않음으로 설정합니다. 해제 후 청크가 할당되지 않은 것으로 확인되면 해제됩니다. 캐시 번호가 특정 값에 도달하면 새로 추가된 청크는 더 이상 캐시되지 않고 메모리가 반환됩니다. 시스템에서는 캐시된 청크를 할당할 때 너무 많은 메모리를 차지하지 않도록 하세요. chached_chunks에서 발견되면 시스템에 적용하지 않고 직접 꺼내서 사용합니다. 3. 소형 릴리스의 경우 릴리스된 슬롯은 상대적으로 헤드만 사용 가능한 규칙 슬롯에 다시 삽입됩니다. 단순한.
관련 권장 사항:
위 내용은 PHP 메모리 관리에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!