2013-09-03 3 views
7

나는 다음과 같은 문제가`와 대용량 메모리 매핑 : 제로 madvise`

내가 MAP_ANONYMOUSmmap를 통해 메모리 (여러 GIB)의 큰 덩어리를 할당합니다. 그 덩어리는 매번 제로가 될 필요가있는 큰 해시 맵을 가지고 있습니다. 각 라운드에서 전체 맵핑을 사용할 수있는 것은 아닙니다 (모든 페이지에 오류가있는 것은 아님). memset은 그리 좋은 생각이 아닙니다. 너무 오래 걸립니다.

신속하게 처리하는 가장 좋은 전략은 무엇입니까?

후속 액세스가 새 빈 페이지를 제공하는 윌

madvise(ptr, length, MADV_DONTNEED); 

보증 나? 리눅스 man madvise 페이지에서

:

(MADV_DONTNEED의 경우를 제외하고) 응용 프로그램의 의미에 영향을 미치지 않습니다,하지만 성능에 영향을 미칠 수있는이 호출. 커널은 조언을 무시해도 무방합니다.

...

MADV_DONTNEED

이후의 성공이 범위의 페이지 액세스,하지만 기본 매핑 파일에서 메모리 내용의 다시로드에 하나 발생합니다 (적 mmap (2) 참조) 기본 파일이없는 매핑의 경우 주문형 페이지가 필요 없습니다. 현재 리눅스 구현 (2.4.0)의 조언으로보다 명령으로 더이 시스템 호출을 볼

...

또는 내가 munmap에있는이 지역을 매핑 할 다시 한번?

그것은 리눅스에서 작동 이상적으로 OS X의

+0

이 테스트 방법은 없지만 FWIW [OSX] (https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/madvise.2. html) 맨 페이지는 'madvise'd 페이지가 0 인 것에 대해 언급하지 않습니다. [posix] (http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_madvise.html) 버전도 아닙니다. 메모리 공간을 다시 mmapping하는 오버 헤드가 큰가요? – Collin

+0

@Collin 지나치게 큰 성능은 아니지만 스레드를 일시 중단하고 필요한 경우 포인터를 새 매핑으로 업데이트해야합니다. 그게 잘못 될 수있는 더 많은 병렬 코드입니다 ... 그리고 저는이 호출이 실제로 어떻게 작동하는지 궁금합니다. –

답변

7

.

+0

고마워,이게 내가 원하는거야. 그것은 내 OS X에서도 작동합니다. –

+3

명확하지 않은 경우, 이전에 mmap 된 메모리의 일부 (또는 전체)를 가리키는 MAP_FIXED 주소로'mmap()'을 다시 실행하는 것이 좋습니다. 문서에 따르면 이전 페이지가 삭제되고 새로운 페이지가 새로 매핑됩니다. –

+0

어떻게하면 성능이 향상됩니까? 커널은 여전히 ​​페이지를 초기화해야합니다. 그래서 이것은 시스템 호출의 오버 헤드가 있고, mmap 논리를 실행 한 다음 페이지를 제로로 만들기 때문에 사용자 공간에 memset이 더 나빠질 것입니다. (비록 OP가 아마도이 질문으로 끝났지 만 여전히 궁금하다. memset이 여전히 여기서 가장 좋은 방법이라고 생각한다.) –

1

madvise 행동은 확실히 표준 아닙니다에서 동일한 동작을한다, 그래서 이것은 휴대용되지 않을 것입니다.

제로 아웃하려는 부분이 매핑 끝 부분에서 발생하면 ftruncate으로 벗어날 수 있습니다.당신은 한 단계 더 소개해야 할 것 :

  1. shm_open은 데이터에 "영구"파일 설명을하기 위해 필요한 크기가 FD의
  2. mmap-
  3. ftruncate

다음을 너는 항상 할 수 있었다

  1. munmap
  2. 실제 길이
  3. ftruncate 짧은 뭔가
  4. ftruncate는 다시

및은 다음 "매핑"일부가 0으로 초기화 될 것

  • mmap
  • 이 필요합니다.

    그러나 시스템이 페이지의 영점 조정을 수행해야한다는 점도 명심하십시오. 컴파일러에서 memset에 대해 생성하는 인라인 스터핑보다 약간 더 효율적일 수 있지만 확실하지는 않습니다. MAP_FIXED 이후

    mmap(ptr, length, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 
    

    memset에 다시 하락, 상당히 임의의 구현 고유의 이유로 실패하도록 허용이 반환하는 경우 MAP_FAILED는 것이 바람직 할 것이다 : 매우 이식 문제에 훨씬 쉽게 솔루션이 있습니다

    +0

    전체 매핑을 0으로 설정하면 길이가 동일하게 유지됩니다. 'munmap' id를 살펴보고 싶다면'munmap','mmap/MAP_ANONYMOUS'를 호출하면됩니다. 이 작업을 복잡하게 수행 할 필요가 없습니다. 정말로 원하는 것은 VM 공간이 일시적으로 매핑 해제되는 단계를 거치지 않고, 페이지가 더러 우면 재사용 될 때까지 물리적 RAM을 해제하는 것이 좋습니다. –

    +1

    'munmap' 다음에'mmap'이 오는 것은 안전하지 않습니다. 경쟁 조건이 있습니다. 범위는 순간적으로 매핑이 해제되어 다른 thread가 그 영역 내에서 매핑을 취득하는지, 또는 그 영역에 액세스하려고하는 것을 세그 폴트합니다. 안전한 접근 방법에 대한 내 대답을보십시오. –

    +0

    @R .., 질문 스레드를 언급하지 않습니다. 하지만 발밑에서 매핑을 변경하면 다른 스레드가 액세스하지 않도록해야합니다. 이것은 응용 프로그램에서 명확하지 않은 경우 이것은 일종의 잠금에 의해 보장되어야합니다. 그러나 그것이 제기 될 때 의문점을 훨씬 뛰어 넘습니다.귀하의 솔루션에는 구현 별 동작에 의존한다는 단점이 있습니다. –

    1

    Linux의 경우 매핑을 제로화하는 익명 매핑에서 MADV_DONTNEED을 신뢰할 수 있습니다. 이것은 휴대 가능하지 않지만 - madvise() 자체는 표준화되지 않았습니다. posix_madvise()은 표준화되었지만 POSIX_MADV_DONTNEED이 아니고은 Linux MADV_DONTNEED 플래그와 동일한 동작을합니다. posix_madvise()은 항상 권고 사항이며 응용 프로그램의 의미에 영향을주지 않습니다.