programing

malloc 구현은 해제 된 메모리를 시스템에 반환합니까?

goodcopy 2021. 1. 15. 19:18
반응형

malloc 구현은 해제 된 메모리를 시스템에 반환합니까?


메모리 할당 해제가 빈번한 수명이 긴 응용 프로그램이 있습니다. malloc 구현이 해제 된 메모리를 시스템에 반환합니까?

이 점에서 다음의 행동은 무엇입니까?

  • ptmalloc 1, 2 (glibc 기본값) 또는 3
  • dlmalloc
  • tcmalloc (구글 스레드 malloc)
  • solaris 10-11 기본 malloc 및 mtmalloc
  • FreeBSD 8 기본 malloc (jemalloc)
  • 몰록을 비축 해?

최신 정보

메모리 사용량이 낮과 밤에 매우 다를 수있는 응용 프로그램이있는 경우 (예) malloc이 해제 된 메모리를 시스템에 반환하도록 강제 할 수 있습니까?

이러한 반환이 없으면 해제 된 메모리는 여러 번 교체되지만 이러한 메모리에는 쓰레기 만 포함됩니다.


다음 분석은 glibc에만 적용됩니다 (ptmalloc2 알고리즘 기반). 해제 된 메모리를 시스템으로 되 돌리는 데 도움이되는 특정 옵션이 있습니다.

  1. mallopt () (에서 정의 됨 malloc.h)는 매개 변수 옵션 중 하나를 사용하여 트림 임계 값을 설정하는 옵션을 제공합니다 M_TRIM_THRESHOLD. 이것은 데이터 세그먼트의 상단에 허용되는 최소 여유 메모리 양 (바이트)을 나타냅니다. 양이이 임계 값 아래로 떨어지면 glibc는 brk()커널에 메모리를 돌려주기 위해 호출 합니다.

    M_TRIM_THRESHOLDLinux에서 의 기본값 은 128K로 설정되며 더 작은 값을 설정하면 공간을 절약 할 수 있습니다.

    환경 변수에 트림 임계 값을 설정 MALLOC_TRIM_THRESHOLD_하여 소스 변경없이 동일한 동작을 수행 할 수 있습니다 .

    그러나를 사용하여 실행 한 예비 테스트 프로그램 M_TRIM_THRESHOLD은 malloc이 할당 한 메모리가 시스템으로 반환 되더라도 처음에 요청한 실제 메모리 청크 (아레나)의 나머지 부분은 brk()유지되는 경향이 있음을 보여줍니다.

  2. malloc_trim(pad)(에서 정의 됨 malloc.h) 을 호출하여 메모리 영역을 정리하고 사용하지 않는 메모리를 시스템에 되돌릴 수 있습니다. 이 함수는 데이터 세그먼트의 크기를 조정하여 최소 pad바이트를 끝에 남겨두고 한 페이지 미만의 바이트를 확보 할 수있는 경우 실패합니다. 세그먼트 크기는 항상 한 페이지의 배수이며 i386에서는 4,096 바이트입니다.

    이 수정 된 free()using 동작에 대한 구현 malloc_trim은 malloc 후크 기능을 사용하여 수행 할 수 있습니다. 이것은 핵심 glibc 라이브러리에 대한 소스 코드 변경이 필요하지 않습니다.

  3. madvise()glibc의 무료 구현 내에서 시스템 호출을 사용 합니다.


대부분의 구현은 (상대적으로 드문) 전체 "블록"(OS에 적합한 크기)이 해제되고 반환 될 수있는 경우를 식별하는 데 신경 쓰지 않지만 물론 예외가 있습니다. 예를 들어, OpenBSD 의 wikipedia 페이지 에서 인용 합니다 .

에 대한 호출 free에서 메모리가 해제되고 munmap을 사용하여 프로세스 주소 공간에서 매핑 해제됩니다. 이 시스템은 OpenBSD의 mmap시스템 호출 의 일부로 구현 된 주소 공간 레이아웃 무작위 화 및 갭 페이지 기능을 활용하여 보안을 향상시키고 , 사용 후 사용 가능 버그를 감지하기 위해 설계되었습니다. 대용량 메모리 할당은 해제 된 후 완전히 매핑 해제됩니다. , 추가로 사용하면 세그먼트 오류가 발생하고 프로그램이 종료됩니다.

하지만 대부분의 시스템은 OpenBSD만큼 보안에 중점을 두지 않습니다.

이 사실을 알면 많은 양의 메모리에 대해 일시적인 것으로 알려진 요구 사항이있는 장기 실행 시스템을 코딩 할 때 항상 fork프로세스를 시도합니다 . 부모는 자식의 결과를 기다립니다 [[ 일반적으로 파이프에서]], 자식이 계산 (메모리 할당 포함)을 수행하고 [[해당 파이프에서]] 결과를 반환 한 다음 종료됩니다. 이런 식으로, 내 장기 실행 프로세스는 가끔씩 메모리 수요가 급증하는 사이의 오랜 시간 동안 쓸모없는 메모리를 차지하지 않을 것입니다. 다른 대체 전략에는 이러한 특수 요구 사항을위한 사용자 지정 메모리 할당 자로 전환하는 것이 포함됩니다 (C ++를 사용하면 합리적으로 쉽게 사용할 수 있지만 Java 및 Python과 같은 가상 머신이있는 언어는 일반적으로 그렇지 않습니다.


나는 OP와 같은 문제를 다루고 있습니다. 지금까지 tcmalloc으로 가능해 보입니다. 두 가지 해결책을 찾았습니다.

  1. tcmalloc이 연결된 프로그램을 컴파일 한 다음 다음과 같이 실행하십시오.

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    문서에 언급되어 있습니다

    합리적인 요금은 [0,10] 범위입니다.

    하지만 10 개로는 충분하지 않은 것 같습니다 (즉, 변화가 없음).

  2. 해제 된 모든 메모리를 해제하는 것이 흥미로운 코드를 찾은 다음 다음 코드를 추가합니다.

    #include "google/malloc_extension_c.h" // C include
    #include "google/malloc_extension.h"   // C++ include
    
    /* ... */
    
    MallocExtension_ReleaseFreeMemory();
    

두 번째 해결책은 제 경우에 매우 효과적이었습니다. 첫 번째는 훌륭하지만 성공하지 못합니다. 예를 들어 올바른 번호를 찾는 것은 복잡합니다.


내 앱에서 비슷한 문제가 발생했습니다. 몇 가지 조사를 한 후 할당 된 개체가 작을 때 (제 경우 120 바이트 미만) 어떤 이유로 glibc가 시스템에 메모리를 반환하지 않는다는 것을 알았습니다.
이 코드를보십시오 :

#include <list>
#include <malloc.h>

template<size_t s> class x{char x[s];};

int main(int argc,char** argv){
    typedef x<100> X;

    std::list<X> lx;
    for(size_t i = 0; i < 500000;++i){
        lx.push_back(X());
    }

    lx.clear();
    malloc_stats();

    return 0;
}

Program output:

Arena 0:
system bytes     =   64069632
in use bytes     =          0
Total (incl. mmap):
system bytes     =   64069632
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

about 64 MB are not return to system. When I changed typedef to: typedef x<110> X; program output looks like this:

Arena 0:
system bytes     =     135168
in use bytes     =          0
Total (incl. mmap):
system bytes     =     135168
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

almost all memory was freed. I also noticed that using malloc_trim(0) in either case released memory to system.
Here is output after adding malloc_trim to the code above:

Arena 0:
system bytes     =       4096
in use bytes     =          0
Total (incl. mmap):
system bytes     =       4096
in use bytes     =          0
max mmap regions =          0
max mmap bytes   =          0

For all 'normal' mallocs, including the ones you've mentioned, memory is released to be reused by your process, but not back to the whole system. Releasing back to the whole system happens only when you process is finally terminated.


Of the ones you list, only Hoard will return memory to the system... but if it can actually do that will depend a lot on your program's allocation behaviour.


The short answer: To force malloc subsystem to return memory to OS, use malloc_trim(). Otherwise, behavior of returning memory is implementation dependent.


FreeBSD 12's malloc(3) uses jemalloc 5.1, which returns freed memory ("dirty pages") to the OS using madvise(...MADV_FREE).

Freed memory is only returned after a time delay controlled by opt.dirty_decay_ms and opt.muzzy_decay_ms; see the manual page and this issue on implementing decay-based unused dirty page purging for more details.

Earlier versions of FreeBSD shipped with older versions of jemalloc, which also returns freed memory, but uses a different algorithm to decide what to purge and when.

ReferenceURL : https://stackoverflow.com/questions/2215259/will-malloc-implementations-return-free-ed-memory-back-to-the-system

반응형