Ich bin in out of memory Ausnahmen in Geräteprotokoll von GPU generiert beim Versuch, schwere Grafik-Szene mit VBO auf Android laden geladen.OpenGL ES VBO seltsame Speicher Auswirkungen
20:53:48.640 app W/Adreno-GSL: <sharedmem_gpumem_alloc_id:2255>: sharedmem_gpumem_alloc: mmap failed errno 12 Out of memory
20:53:48.642 app E/Adreno-GSL: <gsl_memory_alloc_pure:1971>: GSL MEM ERROR: kgsl_sharedmem_alloc ioctl failed.
Die Rohbinärdatengröße, die ich liefern möchte, ist weniger als die Hälfte der verfügbaren RAM-Menge. Nach einigen Recherchen fand ich, dass nach jedem glBufferData(..)
Anruf die Menge an freiem Speicher 2 Mal die Größe der gelieferten Daten abnimmt (auf verschiedenen Geräten versucht, dasselbe Ergebnis). Hier ist mein Setup:
logMem("before buff creation");
ByteBuffer dummyBuff = ByteBuffer.allocateDirect(1024 * 1024 * 16).order(ByteOrder.nativeOrder());
byte[] some = new byte[1024];
for (int i = 0; i < dummyBuff.capacity(); i+= some.length) {
dummyBuff.put(some);
}
dummyBuff.rewind();
logMem("buff data created");
int[] bufferHandles = new int[1];
GLES20.glGenBuffers(1, bufferHandles, 0);
int bufferHandle = bufferHandles[0];
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferHandle);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, dummyBuff.capacity(), dummyBuff, GLES20.GL_STATIC_DRAW);
logMem("buff data supplied");
Speichermenge links mit
manager = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
info = new ActivityManager.MemoryInfo();
...
manager.getMemoryInfo(info);
Log.v("mem", tag + ", mem " + info.availMem/1024/1024);
hier angemeldet ist, was ich im Protokoll bin immer
20:13:34.243 V/mem: before buff creation, mem 1381
20:13:34.466 V/mem: buff data created, mem 1366
20:13:34.500 V/mem: buff data supplied, mem 1334
Ich habe auch versucht, eine Kombination aus
GLES20.glBufferData(.., dummyBuf.capacity(), null, ..);
GLES20.glBufferSubData(.., 0, dummyBuf.capacity(), dummyBuf);
In diesem Fall Nach der Ausführung der ersten Zeile erhielt ich wie erwartet einen Verlust der Puffergröße von 1x, aber mit der zweiten war ein weiterer Pufferspeicher von 1 x Größe verschwunden. Ich versuchte es auf 2 verschiedenen Geräten mit verschiedenen GPUs (Adreno, Mali) und bekam das gleiche Verhalten. Meine Frage ist also: Fehle ich etwas oder ist das ein erwartetes Verhalten? Gibt es eine Möglichkeit, diesen RAM-Einfluss zu verringern, wenn Daten an VBO geliefert werden?
Nun, das war die erste Sache, die ich doppelt überprüft habe, und ja, ich bin sicher, dass diese Daten nicht mehr gespeichert werden - wenn GC Collection im Debug manuell auslösen, konnte ich beobachten, dass es zurückgewonnen wird. Wie Sie aus dem Protokoll entnehmen können, hat sich der Gesamteinfluss auf den Speicher für meinen Code auf das Dreifache der Größe meiner Daten ausgewirkt, aber durch die Auslösung von GC wurde der Wert auf 2 reduziert. – user1581348
Denken Sie daran, dass die meisten Prozesse Seitenzuordnungen im Benutzerbereich aus Gründen der Leistung zwischenspeichern. Wenn "availMem" nur die Anzahl der freien Seiten vom Kernel meldet, ist es nicht an "freie" Seiten gebunden, die in User-Space-Seitenpools (z. B. im Treiber oder im VM-Heap-Manager) gespeichert sind. Die Garbage Collection im GC erzwingt nicht zwangsweise die Rückgabe aller freien Seiten an das Betriebssystem. – solidpixel
Hmm..caching klingt vernünftig, trotzdem würde ich für die Art der Daten, die ich bereitstelle (GL_STATIC_DRAW), erwarten, dass der Treiber den für das Zwischenspeichern verwendeten Speicher freigibt, sobald er in den GPU-Bereich übertragen wird (in einer vernünftigen Zeit). aber es scheint, als ob es nie passiert. Nur um sicher zu sein, dass es kein Java-Problem ist, habe ich den gleichen Code mit JNI ausprobiert und dasselbe Ergebnis erzielt. Interessanterweise hatte das Samsung Galaxy S7 in einem dritten Gerät ein völlig anderes Verhalten, die Speicherspur hatte jedoch keine Corellation mit der Menge an Daten, die ich lieferte. – user1581348