Когда смещение передается по убыванию mmap, вызов mmap не удался - PullRequest
1 голос
/ 16 февраля 2011

под Linux:

#free -m
             total       used       free     shared    buffers     cached
Mem:          1995       1460        534          0         68        432
-/+ buffers/cache:        959       1035
Swap:         2055        743       1311

# cat /proc/sys/vm/overcommit_memory
0

#cat /proc/sys/vm/overcommit_ratio

50

тестовый код 1:

#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)


int main(){
    int j = 0;
    int fd = open("dat.tmp",O_RDWR);
    for(int i = 131071 ; i >= 0; i--){
        ++j;        
        void* r = MMAP(fd,i*4096);
        if(r ==  MAP_FAILED){
            printf("%d,%m\n",j);
            break; 
        }    
    }  
    cout << "done " << j << endl;          
    sleep(5); 
}
##############
error  message :
# ./a.out 
65513,Cannot allocate memory
done 65513
...
#################

тестовый код 2:

#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)

int main(){
    int j = 0;
    int fd = open("dat.tmp",O_RDWR);
    for(int i = 0 ; i <= 131071; i++){
        ++j;        
        void* r = MMAP(fd,i*4096);
        if(r ==  MAP_FAILED){
            printf("%d,%m\n",j);
            break; 
        }    
    }  
    cout << "done " << j << endl;          
    sleep(5); 
}

Это работает, так почему ??????????

1 Ответ

4 голосов
/ 17 февраля 2011

Вот мое предположение.Я предполагаю, что вторая программа просто расширяет внутреннюю структуру данных, описывающую одно отображение, чтобы включить еще одну страницу.Первый мог бы сделать это, но вместо этого он должен был бы расширяться в обратном направлении, и я держу пари, что код специального случая для объединяющихся отображений даже не проверяет это.,Будет некоторое количество отображений, используемых для разделяемых библиотек и т. П., Поэтому вам будет доступно менее 65536 отображений.И 65536 - это размер, который многие ядра используют для структуры данных.

Я бы предложил посмотреть /proc/<pid>/maps и посмотреть, сколько карт указано в каждом случае, когда программа спит.Чтобы облегчить это, вы можете распечатать результат getpid() при печати сообщения «Готово».

Я не могу воспроизвести вашу проблему напрямую, поэтому кажется, что обратный случай был обработанправильно в моей системе.Вывод uname -a в моей системе таков:

Linux a_hostname.somewhere 2.6.35.11-83.fc14.x86_64 #1 SMP Mon Feb 7 07:06:44 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux

Но эта программа повторяет вашу проблему:

#include <iostream>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#define PER_PAGE_SIZE 4096
#define MMAP(fd,offset) mmap (NULL,PER_PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fd,offset)

int main()
{
   using ::std::cout;
   using ::std::endl;
   int j = 0;
   int fd = open("dat.tmp",O_RDWR);
   char catcmd[] = "cat /proc/99999/maps_padding";
   for(int i = 131071 ; i >= 0; i-=2){
      ++j;
      void* r = MMAP(fd,i*4096);
      if(r ==  MAP_FAILED){
         cout << j << ", " << strerror(errno) << '\n';
         break;
      }
   }
   ::std::snprintf(catcmd, sizeof(catcmd), "cat /proc/%d/maps", getpid());
   cout.flush();
   ::std::system(catcmd);
   cout << "done " << j << endl;
   sleep(5);
}

Как вы можете видеть, если вы пропустите на 2 при переходев обратном направлении проблема все еще возникает.И вывод cat /proc/<pid>/maps из звонка на system показывает, что на самом деле существуют тысячи отдельных карт.

Если я перестану пропускать 2 и просто вернусь назад, я получу 2 карты, одна большаяи еще один не такой большой.Ядро объединяет смежные карты в одну карту, если может.

В качестве еще одного подтверждающего доказательства того, что ваша проблема, как я описываю, есть хорошее обсуждение /proc/sys/vm/max_map_count.Установка этой переменной позволяет вам изменить количество карт, и по умолчанию установлено значение 65530.

...