2015-05-12 25 views
10

gebrochen Ich versuche, 784 MiB Speicher zu greifen. Ja, ich weiß, dass viele für ein Telefon 32-Bit, aber der folgende Aufruf gearbeitet, bevor Android 5.0:Android NDK mmap Anruf auf 32-Bit-Geräten nach dem Upgrade auf Lollipop

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

jedoch auf drei verschiedenen Geräten verschiedener Hersteller, auf Android aktualisieren 5.0 diese gebrochen hat. Ich nehme an, dass dies eine Änderung in der Speicherzuordnungsfunktionalität in 5.0 ist; Vielleicht müssen verschiedene Flaggen weitergegeben werden?

Hier ist die Fehlermeldung in logcat zurückgegeben:

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

Die Fehlermeldung scheint ziemlich offensichtlich; Haben Sie überprüft, ob genügend Speicher verfügbar ist? – Phillip

+0

Ich kenne keine zuverlässige Methode, um genau zu prüfen, wie viel Speicher frei und zugänglich ist. Allerdings ist das nicht wirklich der Teil, den ich nicht verstehe - ich verstehe nicht, warum der gleiche Code auf dem gleichen Gerät mit Android 4.4 funktioniert und dann auf 5.0 fehlschlägt. Es ist unwahrscheinlich, dass der Speicherbedarf von Android so stark zugenommen hat. Ich denke, dass es wahrscheinlicher ist, dass ein neues Compiler-Flag oder ähnliches benötigt wird. – sigmabeta

+0

Verwenden Sie einfach 'adb shell free -m' von einem angeschlossenen PC. Wenn Sie keinen Zugriff auf ein Gerät haben, bietet SO verschiedene Lösungen für die Abfrage des verfügbaren Speichers von C in Linux. (Du solltest * wirklich * das tun.) – Phillip

Antwort

4

An der Stelle, wo die mmap(), offene /proc/self/maps und kopieren Sie den Inhalt in eine temporäre Datei, dann überprüfen Sie die Datei in einem Editor fehlschlägt. Sie sollten ein paar Einträge wie diese:

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 

Die Zahlen auf der linken Seite sind virtuelle Adressbereiche (Beginn/Ende) für den Prozess. Wenn Sie ein neues Mapping erstellen, muss es in die Lücke zwischen den Mappings passen.

Im obigen Beispiel gibt es eine schöne große Lücke zwischen dem Ende des ersten Eintrags bei 0x42c00000 und dem Anfang des nächsten bei 0x55281000. Das sind ungefähr 294 MB. Es gibt keinen Platz zwischen den nächsten zwei und nur einen kleinen danach.

Wenn Sie Ihre Prozesslandkarte betrachten und keine Lücke finden, die groß genug ist, um Ihre Datei zu halten, haben Sie Ihre Antwort. Die Region zwischen 0x00000000 und 0xbfffffff ist in der Regel für 32-Bit-Apps verfügbar, aber das App-Framework verbraucht einen großen Teil davon. (Die oberste 1GB ist dem Kernel zugeordnet.)

Meine Vermutung ist, dass einige Kombination von ASLR und Änderungen an der Art, wie virtueller Speicher in Lollipop zugeordnet ist, zu diesem Problem geführt haben. In der Karte, die an this similar question angefügt ist, war die größte gefundene Lücke etwa 300 MB. Es gibt zwei große "Dalvik" Regionen, eine 768MB (bei 12e01000), eine 1.2GB (bei 84d81000). (Da Sie Lollipop betreiben, sind diese eher auf ART als auf Dalvik zurückzuführen, aber anscheinend blieb das Label hängen.)

Eine Möglichkeit besteht darin, dass ART höhere Anforderungen an den virtuellen Speicher stellt als Dalvik, und die großen Zuordnungen machen es für Anwendungen schwierig, große zugeordnete Bereiche zu erhalten. Es ist auch möglich, dass ART aufgrund eines Fehlers zu viel Speicherplatz belegt. Vielleicht möchten Sie auf Marshmallow testen, um festzustellen, ob etwas repariert wurde.

In jedem Fall können Sie kein Mapping erstellen, wenn kein zusammenhängender virtueller Speicheradressbereich groß genug ist, um es aufzunehmen. Mit der App-Framework-Nutzung und den enormen ART-Zuordnungen, die in der anderen Frage zu sehen sind, wäre eine 768 MB-Zuordnung nicht möglich, selbst wenn der virtuelle Adressraum nicht fragmentiert wäre. Sie müssen kleinere Abschnitte der Datei zuordnen und sie möglicherweise während der Arbeit entfernen, um Platz zu schaffen.

Es könnte sich lohnen, einen Fehler auf b.android.com zu archivieren. Hängen Sie eine Kopie Ihrer Prozesslandkartendatei an und legen Sie die Version von Android und Gerät fest.

Für ein bisschen mehr über die Interpretation/proc/Karten-Ausgabe, siehe z.B. this answer.

+0

Dies ist eine ausgezeichnete Antwort. Es wird noch einige Zeit dauern, bis ich mit irgendeiner Lösung dieses Problems experimentieren kann (und in der Zwischenzeit ist das fragliche Projekt auf 64-Bit-Geräte beschränkt), aber das klingt, als würde es zumindest die Frage beantworten warum ein BS-Update den fraglichen Code brach. – sigmabeta

0
  • Ihre Anwendungsbibliothek Recompile Lutscher übereinstimmen und versuchen Sie es erneut
  • Aktualisieren Sie Ihr SDK
  • auf Ihrem Lutscher Achten Sie darauf, Zielplattform zu setzen Anwendungseinstellungen
  • Reduzieren Sie den zugewiesenen Speicher und überprüfen Sie erneut
+0

Ich ziele auf SDK 21 sowohl im Manifest als auch im NDK. Die Menge an Speicher ist nicht verhandelbar. – sigmabeta

0

Haben Sie die Option largeHeap ausprobiert?

In ganz speziellen Fällen können Sie eine größere Heap-Größe von fordern das Attribut largeHeap auf „true“ im Manifest Tag. Wenn Sie dies tun, können Sie getLargeMemoryClass() auf abrufen eine Schätzung der großen Heap-Größe abrufen.

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

Weitere Details:

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

+2

Ich verstehe, dass dies den verwalteten Speicher-Heap und nicht den systemeigenen Code betrifft. Täusche ich mich? – sigmabeta

+0

Wie ich verstehe, ja. – mayo

Verwandte Themen