我在制作一個3D測驗應用的時候遇到一個問題,這是一個地球3D模型應用,使用ByteBuffer.allocateDirect申請堆外記憶體,反復多次進出該應用之后,就會出現OOM現象。在網上查了很多關于ByteBuffer.allocateDirect的資料,沒有找到解決辦法,請教下高手如何解決?
申請記憶體:
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());//設定位元組順序
mVertexBuffer = vbb.asFloatBuffer();//轉換為int型緩沖
mVertexBuffer.put(vertices);//向緩沖區中放入頂點坐標資料
mVertexBuffer.position(0);//設定緩沖區起始位置
釋放:
1、第一種說法是觸發full gc就會回收,但是每次進入和退出應用都呼叫System.gc()沒有起作用,資料說jvm的堆外記憶體無法通過System.gc()釋放。所以這種方法我沒試驗成功。
2、第二種說法:import sun.nio.ch.DirectBuffer ,((DirectBuffer)vbb).cleaner().clean(),但是找不到sun.nio.ch.DirectBuffer 這個類,無法import。
3、第三種說法是反射機制,但是運行時發現getMethod("cleaner")的cleaner找不到出錯
Method cleanerMethod = buffer.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(buffer);
Method cleanMethod = cleaner.getClass().getMethod("clean");
cleanMethod.setAccessible(true);
cleanMethod.invoke(cleaner);
AndroidRuntime Exception:
09-01 15:46:46.212 29144 5690 E AndroidRuntime: FATAL EXCEPTION: GLThread 7970
09-01 15:46:46.212 29144 5690 E AndroidRuntime: Process: com.test.earth, PID: 29144
09-01 15:46:46.212 29144 5690 E AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 3110412 byte allocatio
n with 1374136 free bytes and 1341KB until OOM
09-01 15:46:46.212 29144 5690 E AndroidRuntime: at com.test.earth.component.TestActivity$Ball.<init>(TestActivity.java:562)
09-01 15:46:46.212 29144 5690 E AndroidRuntime: at com.test.earth.component.TestActivity$SceneRenderer.
onSurfaceCreated(TestActivity.java:273)
09-01 15:46:46.212 29144 5690 E AndroidRuntime: at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
09-01 15:46:46.212 29144 5690 E AndroidRuntime: at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:
1259)
uj5u.com熱心網友回復:
我搜索到http://blog.csdn.net/aitangyong/article/details/39323125文章里說ByteBuffer.allocateDirect系統會自動釋放記憶體,我按照文章里做了個死回圈申請記憶體,列印結果確實是堆外記憶體沒有增加。這就尷尬了,我的3D代碼難道會是“除非堆記憶體中的ByteBuffer物件由于錯誤編碼而出現記憶體泄露”?那似乎可以找到問題根本原因,就不用糾結上述的問題了。可惜博主精彩的文章戛然而止,未能夠尋找到為何會因為錯誤編碼導致記憶體泄露,還望各位高手不吝指教,謝謝!
1、首先我們看下NIO中提供的ByteBuffer
import java.nio.ByteBuffer;
public class TestDirectByteBuffer
{
// -verbose:gc -XX:+PrintGCDetails -XX:MaxDirectMemorySize=40M
public static void main(String[] args) throws Exception
{
while (true)
{
ByteBuffer buffer = ByteBuffer.allocateDirect(10 * 1024 * 1024);
}
}
}
我們將最大堆外記憶體設定成40M,運行這段代碼會發現:程式可以一直運行下去,不會報OutOfMemoryError。如果使用了-verbose:gc -XX:+PrintGCDetails,會發現程式頻繁的進行垃圾回識訓動。于是我們可以得出結論:ByteBuffer.allocateDirect分配的堆外記憶體不需要我們手動釋放,而且ByteBuffer中也沒有提供手動釋放的API。也即是說,使用ByteBuffer不用擔心堆外記憶體的釋放問題,除非堆記憶體中的ByteBuffer物件由于錯誤編碼而出現記憶體泄露。
uj5u.com熱心網友回復:
最后咋解決了轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/250345.html
標籤:Android
