2015-05-12 37 views
10

Sto provando ad afferrare 784 MiB di memoria. Sì, lo so che è un sacco per un telefono a 32-bit, ma la seguente chiamata lavorato prima di Android 5.0:Chiamata NDAP Android NDK interrotta su dispositivi a 32 bit dopo l'aggiornamento a Lollipop

mmap(0, 0x31000000, PROT_NONE, MAP_ANON | MAP_SHARED, -1, 0); 

Tuttavia, su tre diversi dispositivi di diversi produttori, l'aggiornamento a Android 5.0 ha rotto questo. Presumo che questo è un cambiamento nella funzionalità di allocazione della memoria in 5.0; forse è necessario far passare bandiere diverse?

Ecco il messaggio di errore restituito in logcat:

E/libc﹕ mmap fail (pid 9994, tid 10125, size 822083584, flags 0x21, errno 12(Out of memory)) 
+0

Il messaggio di errore sembra abbastanza ovvio; hai controllato che ci sia abbastanza memoria disponibile? – Phillip

+0

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

+0

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

risposta

4

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.

+0

Questa è una risposta eccellente. Passerà un po 'di tempo prima che mi metta a sperimentare qualsiasi tipo di soluzione a questo problema (e nel frattempo il progetto in questione è limitato ai soli dispositivi a 64 bit), ma sembra che risponda almeno alla domanda del perché un aggiornamento del SO ha rotto il codice in questione. – sigmabeta

0
  • ricompilare la libreria applicazione per abbinare lecca-lecca e riprovare
  • Aggiorna il tuo SDK
  • assicurarsi di impostare piattaforma di destinazione al lollipop sul tuo impostazioni dell'applicazione
  • Ridurre la memoria allocata e ricontrollare
+0

Ho scelto l'SDK 21 sia nel file manifest che in NDK. La quantità di memoria necessaria non è negoziabile. – sigmabeta

0

Hai provato l'opzione largeHeap?

In situazioni molto particolari, è possibile richiedere una dimensione heap più grande dal impostando l'attributo largeHeap su "true" nel tag manifesto. In tal caso, è possibile chiamare getLargeMemoryClass() su ottenere una stima della dimensione dell'heap di grandi dimensioni.

https://developer.android.com/training/articles/memory.html#CheckHowMuchMemory

piu 'dettagli:

https://developer.android.com/guide/topics/manifest/application-element.html#largeHeap

+2

È a mia conoscenza che ciò influisce sull'heap della memoria gestita e non sul codice nativo. Mi sbaglio? – sigmabeta

+0

Come ho capito, si. – mayo