2013-08-03 15 views
4

我正在使用OpenGl Es庫來渲染3D對象。我得到例外OutofMemoryError我試過並搜索谷歌,但無法取得成功異常OutofMemoryError dalvik.system.VMRuntime.newNonMovableArray(本地方法)

請幫我解決這個問題。

package com.amplimesh.models; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 
import java.util.ArrayList; 
import java.util.StringTokenizer; 

import javax.microedition.khronos.opengles.GL10; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.opengl.GLUtils; 
import android.util.Log; 

import com.amplimesh.util.Point3; 

public class ObjModel { 

    public void bindTextures(Context context, GL10 gl) { 
     Bitmap bitmap; 
     try { 
      InputStream is = context.getAssets().open("textures/"+mTextureName); 
      bitmap = BitmapFactory.decodeStream(is); 
      if (bitmap == null) { 
       Log.v("ObjModel", "err loading bitmap!"); 
      } 
     } catch (java.io.IOException e) { 
      Log.v("ObjModel", "err loading tex: "+e.toString()); 
      return; 
     } 

     mTextures = new int[1]; 
     gl.glGenTextures(1, mTextures, 0); 
     gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); 
     gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 
     bitmap.recycle(); 
    } 

    public void draw(GL10 gl) { 
     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
     gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 
     for (Model model : mModels) { 

      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.v); 
      if (model.vt != null && mTextures != null) { 
       gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]); 
       gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, model.vt); 
      } 

      if (model.vn != null) { 
       gl.glNormalPointer(GL10.GL_FLOAT, 0, model.vn); 
      } 
      gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.v_size); 

     } 

     gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); 
     gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    } 

    public static ObjModel loadFromStream(InputStream is, String texture_name) throws IOException { 
     ObjModel obj = ObjLoader.loadFromStream(is); 
     obj.mTextureName = texture_name; 
     return obj; 
    } 

    private Model mModels[]; 
    private int mTextures[]; 
    private String mTextureName; 

    /** 
    * It help to load the obj. 
    * @author Ajay 
    */ 
    private static class ObjLoader { 

     public static ObjModel loadFromStream(InputStream is) throws IOException { 
      BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
      ObjModel obj = new ObjModel(); 
      ArrayList<Point3> v = new ArrayList<Point3>(); 
      ArrayList<Point3> vt = new ArrayList<Point3>(); 
      ArrayList<Point3> vn = new ArrayList<Point3>(); 
      ArrayList<Face> f = new ArrayList<Face>(); 

      ArrayList<Model> o = new ArrayList<Model>(); 

      boolean o_pending=false; 

      while(reader.ready()) { 
       String line = reader.readLine(); 
       if (line == null) 
        break; 

       StringTokenizer tok = new StringTokenizer(line); 
       String cmd = tok.nextToken(); 

       if (cmd.equals("o")) { 
        if (o_pending) { 
         Model model = new Model(); 
         model.fill(f, vt.size() > 0, vn.size() > 0); 
         o.add(model); 
        } 
        else { 
         o_pending=true; 
        } 
       } 
       else 
        if (cmd.equals("v")) { 
         v.add(read_point(tok)); 
        } 
        else 
         if (cmd.equals("vn")) { 
          vn.add(read_point(tok)); 
         } 
         else 
          if (cmd.equals("vt")) { 
           vt.add(read_point(tok)); 
          } 
          else 
           if (cmd.equals("f")) { 
            if (tok.countTokens() != 3) 
             continue; 

            Face face = new Face(3); 
            while (tok.hasMoreTokens()) { 
             StringTokenizer face_tok = new StringTokenizer(tok.nextToken(), "/"); 

             int v_idx = -1; 
             int vt_idx = -1; 
             int vn_idx = -1; 
             v_idx = Integer.parseInt(face_tok.nextToken()); 
             if (face_tok.hasMoreTokens()) vt_idx = Integer.parseInt(face_tok.nextToken()); 
             if (face_tok.hasMoreTokens()) vn_idx = Integer.parseInt(face_tok.nextToken()); 

             //Log.v("objmodel", "face: "+v_idx+"/"+vt_idx+"/"+vn_idx); 

             face.addVertex(
               v.get(v_idx-1), 
               vt_idx == -1 ? null : vt.get(vt_idx-1), 
                 vn_idx == -1 ? null : vn.get(vn_idx-1) 
               ); 
            } 
            f.add(face); 
           } 
      } 

      if (o_pending) { 
       Model model = new Model(); 
       model.fill(f, vt.size() > 0, vn.size() > 0); 
       o.add(model); 
      } 

      obj.mModels = new Model[o.size()]; 
      o.toArray(obj.mModels); 
      return obj; 
     } 



     private static Point3 read_point(StringTokenizer tok) { 
      Point3 ret = new Point3(); 
      if (tok.hasMoreTokens()) { 
       ret.x = Float.parseFloat(tok.nextToken()); 
       if (tok.hasMoreTokens()) { 
        ret.y = Float.parseFloat(tok.nextToken()); 
        if (tok.hasMoreTokens()) { 
         ret.z = Float.parseFloat(tok.nextToken()); 
        } 
       } 
      } 
      return ret; 
     } 

    } 

    private static class Face { 
     Point3 v[]; 
     Point3 vt[]; 
     Point3 vn[]; 
     int size; 
     int count; 

     public Face(int size) { 
      this.size = size; 
      this.count = 0; 
      this.v = new Point3[size]; 
      this.vt = new Point3[size]; 
      this.vn = new Point3[size]; 
     } 

     public boolean addVertex(Point3 v, Point3 vt, Point3 vn) { 
      if (count >= size) 
       return false; 
      this.v[count] = v; 
      this.vt[count] = vt; 
      this.vn[count] = vn; 
      count++; 
      return true; 
     } 

     public void pushOnto(FloatBuffer v_buffer, FloatBuffer vt_buffer, FloatBuffer vn_buffer) { 
      int i; 
      for (i=0; i<size; i++) { 
       v_buffer.put(v[i].x); v_buffer.put(v[i].y); v_buffer.put(v[i].z); 

       if (vt_buffer != null && vt[i] != null) { 
        vt_buffer.put(vt[i].x); vt_buffer.put(vt[i].y); 
       } 

       if (vn_buffer != null && vn[i] != null) { 
        vn_buffer.put(vn[i].x); vn_buffer.put(vn[i].y); vn_buffer.put(vn[i].z); 
       } 
      } 
     } 
    } 


    private static class Model { 
     public FloatBuffer v; 
     public FloatBuffer vt; 
     public FloatBuffer vn; 
     public int v_size; 

     public void fill(ArrayList<Face> faces, boolean has_tex, boolean has_normals) { 
      int f_len = faces.size(); 

      this.v_size = f_len * 3; 

      ByteBuffer tBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
      tBuf.order(ByteOrder.nativeOrder()); 
      this.v = tBuf.asFloatBuffer(); 

      if (has_tex) { 
       ByteBuffer vtBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
       vtBuf.order(ByteOrder.nativeOrder()); 
       this.vt = vtBuf.asFloatBuffer(); 
      } 

      if (has_normals) { 
       ByteBuffer vnBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
       vnBuf.order(ByteOrder.nativeOrder()); 
       this.vn = vnBuf.asFloatBuffer(); 
      } 

      int i; 
      for (i=0; i < f_len; i++) { 
       Face face = faces.get(i); 
       face.pushOnto(this.v, this.vt, this.vn); 
      } 

      this.v.rewind(); 
      if (this.vt != null) 
       this.vt.rewind(); 
      if (this.vn != null) 
       this.vn.rewind(); 
     } 
    } 
} 

堆棧跟蹤

08-03 16:22:31.794: E/AndroidRuntime(18878): FATAL EXCEPTION: AsyncTask #3 
08-03 16:22:31.794: E/AndroidRuntime(18878): java.lang.RuntimeException: An error occured while executing doInBackground() 
08-03 16:22:31.794: E/AndroidRuntime(18878): at android.os.AsyncTask$3.done(AsyncTask.java:278) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.lang.Thread.run(Thread.java:856) 
08-03 16:22:31.794: E/AndroidRuntime(18878): Caused by: java.lang.OutOfMemoryError 
08-03 16:22:31.794: E/AndroidRuntime(18878): at dalvik.system.VMRuntime.newNonMovableArray(Native Method) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.nio.MemoryBlock.allocate(MemoryBlock.java:126) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.nio.ReadWriteDirectByteBuffer.<init>(ReadWriteDirectByteBuffer.java:46) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:68) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at com.amplimesh.models.ObjModel$Model.fill(ObjModel.java:241) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at com.amplimesh.models.ObjModel$ObjLoader.loadFromStream(ObjModel.java:161) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at com.amplimesh.models.ObjModel.loadFromStream(ObjModel.java:74) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at com.amplimesh.renderer.RendererView$ObjLoaderAsync.doInBackground(RendererView.java:443) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at com.amplimesh.renderer.RendererView$ObjLoaderAsync.doInBackground(RendererView.java:1) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at android.os.AsyncTask$2.call(AsyncTask.java:264) 
08-03 16:22:31.794: E/AndroidRuntime(18878): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
08-03 16:22:31.794: E/AndroidRuntime(18878): ... 5 more 
+0

當應用程序崩潰? –

+0

它讀取obj文件並加載對象時。請檢查logcat和代碼,並幫助我處理此問題 – user2601652

回答

14

嘗試啓用大型堆支持,加入這個AndroidManifest.xml檔案:

<application android:largeHeap="true" 

此外,您還可以降低你的位圖所要求的存儲使用Bitmap.Config類型RGB_565而不是ARGB_8888。

+3

這不是OutOfMemoryExceptions的解決方案。在訴諸增加堆大小之前清理內存泄漏。查看LeakCanary庫以幫助識別上下文泄漏。 – 2016-04-11 14:20:04

+0

我遇到了Android 5和6設備的問題。 Sei un cazzo di dio。 – UserK

-1

只需將圖像文件添加到drawable或mipmap的xhdpi中即可。這對我有效。