2016-05-24 5 views
7

Ich hatte den Eindruck von der mmap(2) man-Seite und den Suchergebnissen, dass mmap ist nur auf System verfügbaren Adressräume beschränkt, abzüglich der System reservierten Adressräume. Also auf 32-Bit-armv7l nehme ich an, es ist um 3GB = (4GB - 1GB).Warum mmap eine 4GB-Datei auf 32-Bit-armv7l erfolgreich?

Aber es schien, wie ich konnte tatsächlich mmap eine 5 GB-Datei ohne Probleme:

int main(int argc, char** argv) { 
     // stats 
     char * path = argv[1]; 
     struct stat sb; 
     stat(path, &sb); 
     std::cout << "File size: " << sb.st_size << std::endl; 

     // open 
     int fd = open(path, O_RDONLY, S_IRWXU); 
     std::cout << "File descriptor: " << fd << std::endl; 
     int i; 
     for (i =0; i<10; ++i){ 
       void *pa = mmap(
         nullptr, sb.st_size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); 
       std::cout << "PA: " << pa 
         << ", MAP_FAILED: " 
         << (pa == MAP_FAILED) << ", Status: " 
         << strerror(errno) << std::endl; 
     } 
} 

Compile mit -D_FILE_OFFSET_BITS=64 Flagge:

g++ -D_FILE_OFFSET_BITS=64 test.cc 

und das Ergebnis liefert:

File size: 5045966585 
File descriptor: 3 
PA: 0x89f80000, MAP_FAILED: 0, Status: Success 
PA: 0x5d34a000, MAP_FAILED: 0, Status: Success 
PA: 0x30714000, MAP_FAILED: 0, Status: Success 
PA: 0x3ade000, MAP_FAILED: 0, Status: Success 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 
PA: 0xffffffff, MAP_FAILED: 1, Status: Cannot allocate memory 

Von den Ergebnissen gelang es mmap viermal, bevor es in echte Trou ging bles. Aber es sollte nicht erfolgreich gewesen sein, da die Datei ~ 5GB ist.

Meine Fragen wären:

  1. dieses Verhalten für mmap erwartet?
  2. Wenn nicht, wo habe ich falsch gemacht?

Edit:

Mit physikalischen addres Erweiterung (PAE) 32-Bit-Systeme können addres viel mehr als 2^32 Bytes, wenn die verfügbar ist.

Es gibt keine PAE-Unterstützung für diese CPU

$> cat /proc/cpuinfo 

Processor  : ARMv7 Processor rev 4 (v7l) 
processor  : 0 
BogoMIPS  : 1436.46 

processor  : 1 
BogoMIPS  : 1436.46 

Features  : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt 
CPU implementer : 0x41 
CPU architecture: 7 
CPU variant  : 0x0 
CPU part  : 0xc07 
CPU revision : 4 

Hardware  : sun7i 
Revision  : 0000 
Serial   : 09c11b9d52544848804857831651664b 
+1

Nicht verwandt mit Ihrer Frage und nur zur Info, aber wenn Sie einen Zeiger mit dem 'printf' Format' "% p" 'das Argument * sollte * ein' void * ', also kein Casting benötigt. Es gibt auch eine [output operator overload] (http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt), die ein 'void *' verwendet, um Zeiger zu drucken, also keine Notwendigkeit für das alte C 'printf 'Funktion überhaupt. –

+0

Mit einer physischen Adresserweiterung (PAE) können 32-Bit-Systeme viel mehr als 2^32 Bytes adressieren, wenn diese verfügbar sind. – hetepeperfan

+6

Was ist der Funktionsprototyp für 'mmap()'? Wenn das zweite Argument nur 32 Bit ist, wird die 64-Bit-Datei "sb.st_size" möglicherweise abgeschnitten. –

Antwort

6

PAE ist irrelevant. Es geht nicht um den Zugriff auf große Mengen an physischem Speicher.

Das Problem ist, dass Ihre mmap-Funktion einen 32-Bit-Wert für die Größe des Mappings verwendet. Daher wird Ihre 64-Bit-Größe abgeschnitten und Sie reservieren tatsächlich weniger als 1 GB virtuellen Speicher.