當我嘗試使用Android上的VBO加載沉重的圖形場景時,我遇到了由GPU生成的設備日誌中的內存不足異常。OpenGL ES VBO奇怪的內存影響
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.
我試圖提供的原始二進制數據大小不到RAM的可用數量的一半。在做了一些研究之後,我發現在每次調用glBufferData(..)
後,可用內存量減少了所提供數據大小的兩倍(在不同設備上嘗試,結果相同)。這裏是我的設置:
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");
的記憶中留下的量記錄與
manager = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
info = new ActivityManager.MemoryInfo();
...
manager.getMemoryInfo(info);
Log.v("mem", tag + ", mem " + info.availMem/1024/1024);
以下是我在日誌中我得到
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
我也嘗試過的
組合 GLES20.glBufferData(.., dummyBuf.capacity(), null, ..);
GLES20.glBufferSubData(.., 0, dummyBuf.capacity(), dummyBuf);
在這種情況下第一行執行後,我得到了1x緩衝區大小的損失,但是第二次,另一個1x緩衝區大小的內存消失了。 我在使用不同GPU(Adreno,Mali)的2種不同設備上試過它,並獲得相同的行爲。所以,我的問題是:我錯過了什麼,或者這是一個預期的行爲?向VBO提供數據時有什麼辦法可以減少這種RAM影響?
那麼,這是我第一次加倍檢查,是的,我敢肯定,這些數據不再存儲 - 當在調試中手動觸發GC採集時,我可以觀察到它被回收。從日誌中可以看到,我的代碼對內存的總體影響是我數據大小的3倍,但觸發GC確實將其修剪爲2次。 – user1581348
還記得大多數進程會因性能原因而在用戶空間中緩存頁面分配。如果'availMem'只是報告內核的空閒頁數,那麼它就會忘記在用戶空間頁面池中保存的任何「空閒」頁面(例如在驅動程序或VM堆管理器中)。 GC中的垃圾收集不一定會強制將所有空閒頁面返回給操作系統。 – solidpixel
嗯..緩存聽起來仍然合理,但對於我提供的數據的性質(GL_STATIC_DRAW),我希望驅動程序一旦將其傳輸到GPU空間(在合理的時間內)就釋放用於緩存的內存,但似乎從未發生過。爲了確保它不是Java問題,我使用JNI嘗試了相同的代碼,獲得相同的結果。有趣的是,在第三個設備中,三星Galaxy S7的行爲完全不同,內存跟蹤與我提供的數據量沒有關係。 – user1581348