Nel punto in cui il mmap()
fallisce, aperto /proc/self/maps
e copiare il contenuto di un file temporaneo, quindi esaminare il file in un editor. Si dovrebbe vedere un gruppo di voci come queste:
12e01000-42c00000 ---p 00201000 00:04 11639 /dev/ashmem/dalvik-main space (deleted)
55281000-5d500000 r--s 00000000 00:16 61 /storage/sdcard1/blah
5d500000-67e80000 rw-p 00000000 00:00 0 [anon:libc_malloc]
67ea4000-682cc000 r-xp 00000000 b3:17 114807 /system/vendor/lib/libsc-a3xx.so
682cc000-682f4000 r--p 00427000 b3:17 114807 /system/vendor/lib/libsc-a3xx.so
I numeri sulla sinistra sono intervalli di indirizzi virtuali (inizio/fine) per il processo. Quando crei una nuova mappatura, deve inserirsi nel divario tra i mapping.
Nell'esempio precedente, c'è un bel divario tra la fine della prima voce a 0x42c00000 e l'inizio della successiva a 0x55281000. Questo è circa 294 MB. Non c'è spazio tra i due successivi, e solo uno più piccolo dopo.
Se osservate la vostra mappa dei processi e non trovate una fessura abbastanza grande da contenere il vostro file, avete la vostra risposta. La regione compresa tra 0x00000000 e 0xbfffffff è generalmente disponibile per le app a 32 bit, ma la struttura delle app ne fa uso in gran parte. (Il primo 1 GB è mappato al kernel.)
La mia ipotesi è che alcune combinazioni di ASLR e modifiche al modo in cui la memoria virtuale è allocata in Lollipop hanno portato a questo problema. Nella mappa allegata allo this similar question, la distanza maggiore rilevata era di circa 300 MB. Ci sono due grandi regioni "dalvik", una da 768 MB (a 1201000), una da 1,2 GB (a 84d81000). (Dato che stai usando Lollipop, questi sono in realtà dovuti a ART piuttosto che a Dalvik, ma a quanto pare l'etichetta è rimasta bloccata.
Una possibilità è che ART abbia requisiti di memoria virtuale più elevati rispetto a quelli di Dalvik e le grandi allocazioni rendono difficile per le applicazioni ottenere aree mappate di grandi dimensioni. È anche possibile che ART stia sovra-allocando a causa di un bug. Potresti voler provare su Marshmallow per vedere se qualcosa è stato corretto.
In ogni caso, non è possibile creare una mappatura se non esiste un'area di memoria virtuale contigua abbastanza grande da trattenerla. Con l'utilizzo del framework dell'app e le enormi allocazioni ART viste nell'altra domanda, una mappatura di 768 MB non sarebbe possibile anche se lo spazio degli indirizzi virtuali non fosse frammentato. Dovrai mappare sezioni più piccole del file e possibilmente disunificarle mentre lavori per creare spazio.
Potrebbe essere utile archiviare un bug su b.android.com. Allegare una copia del file della mappa dei processi ed essere specifici sulla versione di Android e del dispositivo.
Per ulteriori informazioni sull'interpretazione dell'output di/proc/maps, vedere ad es. this answer.
Il messaggio di errore sembra abbastanza ovvio; hai controllato che ci sia abbastanza memoria disponibile? – Phillip
Non conosco un metodo efficace per verificare esattamente quanta memoria è disponibile e accessibile dal codice nativo. Tuttavia, non è proprio la parte che non capisco - non capisco perché lo stesso codice funzionerebbe sullo stesso dispositivo con Android 4.4 e quindi fallisce su 5.0. È improbabile che l'impronta di memoria di Android sia aumentata di molto: credo sia più probabile che sia necessario un nuovo flag per il compilatore, o qualcosa del genere. – sigmabeta
Basta usare 'adb shell free -m' da un PC connesso. Se non si ha accesso a un dispositivo, SO ha varie soluzioni su come interrogare la memoria disponibile da C in linux. (Dovresti farlo * veramente *) – Phillip