OutofMemoryError While Unzipping Compressed Textures

Started by suheyb1991, January 16, 2015, 10:33:17 AM

Previous topic - Next topic

suheyb1991

I load four images. Images have 2048*1024 resolution. I compress textures for avoid outofmemoryerror but while unzipping textures I get outofmemory error. This error doesn't always happen. Here is my code and log.

MyRenderer.java

Quotepackage com.example.jcptlib;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Vector;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

import com.anka.geo.data.AsynImageDownloader;
import com.anka.geo.data.JSONDatas;
import com.anka.geo.data.events.AsynImageEvent;
import com.anka.geo.data.events.MainRendererEvent;
import com.anka.geo.display.ArrowManager;
import com.anka.geo.display.IUpdateable;
import com.anka.geo.display.Label;
import com.anka.geo.display.Object3DTransformer;
import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.MemoryHelper;

public class MyRenderer implements Renderer {

   public static String IMAGE_PATH = "http://212.156.127.250:7080/panaromik/";
   public static String BACK_END_PATH = "";
   public static String CURRENT_IMAGE_SIZE = "/4096x2048/";
   public static JSONDatas CURRENT_JSON_DATA;

   private FrameBuffer fb;
   private World world;
   private Object3D[] mainSphere = new Object3D[4];;
   // private Object3D[] spheres = new Object3D[4];
   private AssetManager assets;
   private ArrowManager arrowMan;
   private Object3D arrowSample;
   Texture texture1, texture2, texture3, texture4;
   int finCtrl = 0;

   private MainRendererEvent.PrepareEvent preEvent;

   private Vector<IUpdateable> updateables = new Vector<IUpdateable>();

   public World getWorld() {
      return world;
   }

   public FrameBuffer getBuffer() {
      return fb;
   }

   public MyRenderer(Resources resources, AssetManager assets,
         MainRendererEvent.PrepareEvent preEvent) {
      this(resources, assets);
      this.preEvent = preEvent;
   }

   public MyRenderer(Resources resources, AssetManager assets) {
      this.assets = assets;
   }

   @Override
   public void onSurfaceCreated(GL10 gl, EGLConfig config) {
   }

   @Override
   public void onSurfaceChanged(GL10 gl, int width, int height) {

      if (fb != null) {
         fb.dispose();
      }

      fb = new FrameBuffer(width, height); // OpenGL ES 2.0 constructor

      if (world == null) {

         world = new World();

         LoadObjects();

      } else {
         world.dispose();
         world = new World();
         LoadObjects();
      }

   }

   private SimpleVector sphereTR;
   public Camera cam;
   public String filePath;

   public void Load2() {

   }

   public void LoadObjects() {

      world.setAmbientLight(255, 255, 255);

      cam = world.getCamera();

      InputStream ins;
      try {
         ins = assets.open("kure_yeni.3ds");
         mainSphere = loadModel(ins, 1.0f);

         Log.e("Kure","Loaded");
         ins = assets.open("ok.3ds");
         arrowSample = loadModel(ins, 0.1f)[0];

         ins = assets.open("label.3ds");
         Label.labelSample = loadModel(ins, 0.3f)[0];

      } catch (IOException e) {
         e.printStackTrace();
      }

      HashSet<String> textures = TextureManager.getInstance().getNames();

      if (!textures.contains("texture1")) {

         initializeAssets();

         createRotatingObject();

         if (preEvent != null) {
            preEvent.OnInitialized();
         }

      } else {
         // replace texture kullan�lacak

         // Sonra doldurulacak

      }

      if (finCtrl == 1) {
         loadSphere();
         Log.i("fin", "ctr");
      }

   }

   private void loadSphere() {
      mainSphere[0].setTexture("texture4");
      mainSphere[0].setCulling(true);
      mainSphere[0].setShadingMode(Object3D.LIGHTING_NO_LIGHTS);
      mainSphere[0].build();

      mainSphere[1].setTexture("texture1");
      mainSphere[1].setCulling(true);
      mainSphere[1].setShadingMode(Object3D.LIGHTING_NO_LIGHTS);
      mainSphere[1].build();

      mainSphere[2].setTexture("texture2");
      mainSphere[2].setCulling(true);
      mainSphere[2].setShadingMode(Object3D.LIGHTING_NO_LIGHTS);
      mainSphere[2].build();

      mainSphere[3].setTexture("texture3");
      mainSphere[3].setCulling(true);
      mainSphere[3].setShadingMode(Object3D.LIGHTING_NO_LIGHTS);
      mainSphere[3].build();

      sphereTR = new SimpleVector();
      sphereTR.x = 0.01f;
      sphereTR.y = 0;
      sphereTR.z = 0;

      mainSphere[0].translate(sphereTR);
      mainSphere[1].translate(sphereTR);
      mainSphere[2].translate(sphereTR);
      mainSphere[3].translate(sphereTR);

      cam.lookAt(mainSphere[0].getTransformedCenter());
      cam.setFOVLimits(0.4f, 2.5f);
      MemoryHelper.compact();
      Log.i("mainSphere", "loaded");
      world.addObject(mainSphere[0]);
      world.addObject(mainSphere[1]);
      world.addObject(mainSphere[2]);
      world.addObject(mainSphere[3]);
      
      
   }

   // private float rot = 0.1f;

   private void initializeAssets() {
      InputStream insP = null;
      try {
         insP = assets.open("ok.png");
      } catch (IOException e) {
         e.printStackTrace();
      }
      BitmapFactory.Options opts = new BitmapFactory.Options();
      Bitmap bm = BitmapFactory.decodeStream(insP, null, opts);
      Texture arrowTex = new Texture(bm);
      arrowTex.setMipmap(false);

      TextureManager.getInstance().addTexture("arrow", arrowTex);
   }

   private Object3D testOBJ;
   @SuppressWarnings("unused")
   private Object3D cube;

   @SuppressWarnings("unused")
   private void createTestObjects() {

      for (int i = 0; i < 10; i++) {

         testOBJ = Primitives.getCube(10);

         world.addObject(testOBJ);
         float x = (float) (100 + Math.random() * 500);
         float y = (float) (100 + Math.random() * 500);
         testOBJ.translate(x, y, 0);
         testOBJ.setTexture("texture");
         testOBJ.calcTextureWrap();

         testOBJ.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
      }

   }

   private Object3DTransformer cubeTransformer;

   private void createRotatingObject() {
      arrowMan = new ArrowManager(null, world, arrowSample);
      world.addObject(arrowMan);

      cubeTransformer = new Object3DTransformer(arrowMan);
      updateables.add(cubeTransformer);
      updateables.add(arrowMan);
   }

   public void setPickingScreenCoordinates(int x, int y) {
      SimpleVector dir = Interact2D.reproject2D3DWS(cam, fb, x, y)
            .normalize();
      Object[] res = world.calcMinDistanceAndObject3D(cam.getPosition(), dir,
            10000 /* or whatever */);

      for (int i = 0; i < res.length; i++) {
         if (res instanceof Object3D) {
            Object3D tempObject3d = (Object3D) res;
            tempObject3d.rotateY(1);
         }
      }

   }

   @SuppressWarnings("unused")
   private float radTest = 0;

   @Override
   public void onDrawFrame(GL10 gl) {

      if (cubeTransformer != null) {

         float camY = MyGlSurface.globalRotY;
         double camyRad = camY + (Math.PI / 2);// / 180 * Math.PI;

         float xpos = (float) (300 * Math.cos(camyRad));
         float zpos = (float) (300 * Math.sin(camyRad));

         cubeTransformer.setX(xpos);
         cubeTransformer.setZ(zpos);
         cubeTransformer.setY(100);
      }

      for (int i = 0; i < updateables.size(); i++) {
         updateables.get(i).update();
      }
      
         fb.clear(0x000000);
         world.renderScene(fb);
         world.draw(fb);
         fb.display();
      

      

   }

   private Object3D[] loadModel(InputStream filename, float scale) {

      Object3D[] model = Loader.load3DS(filename, scale);
      Object3D[] modMod = new Object3D[model.length];
      Object3D temp = null;
      for (int i = 0; i < model.length; i++) {
         temp = model;
         temp.setCenter(SimpleVector.ORIGIN);
         temp.rotateX((float) (-.5 * Math.PI));
         temp.rotateMesh();
         temp.setRotationMatrix(new Matrix());
         temp.build();
         modMod = temp;
      }
      return modMod;
   }

   public void onUp(int x, int y) {
   }

   public void onMove(int x, int y) {

   }

   public void onDown(int x, int y) {
   }

   public void setCurrentPanaromicData(JSONDatas jdt) {

      CURRENT_JSON_DATA = jdt;
      String gungor = null;
      String dirname = null;
      try {
         gungor = URLEncoder.encode("GÜNGÖREN_JPG", "utf-8");
         dirname = URLEncoder.encode(jdt.getDirname(), "utf-8");
         dirname = dirname.replace("+", "%20");

      } catch (UnsupportedEncodingException e) {
         e.printStackTrace();
      }
      String path = IMAGE_PATH + gungor + "//" + dirname + CURRENT_IMAGE_SIZE
            + jdt.getImg();
      setTextureByPath(path);

   }

   private void setTextureByPath(String path) {

      try {

         AsynImageDownloader asynIma = new AsynImageDownloader();

         asynIma.execute(path, new AsynImageEvent.ImageEvent() {
            @Override
            public void onComplete(Bitmap[] arrayBitmap) {

               System.gc();
               if (arrayBitmap != null) {
                  Log.d("BÄ°TMAP NULL Mı?", "NOT NULL");

                  System.gc();

                  texture1 = new Texture(arrayBitmap[0]);
                  texture1.setMipmap(false);
                  texture1.compress();
                  TextureManager.getInstance().addTexture("texture1",
                        texture1);

                  texture2 = new Texture(arrayBitmap[1]);
                  texture2.setMipmap(false);
                  texture2.compress();
                  TextureManager.getInstance().addTexture("texture2",
                        texture2);

                  texture3 = new Texture(arrayBitmap[2]);
                  texture3.setMipmap(false);
                  texture3.compress();
                  TextureManager.getInstance().addTexture("texture3",
                        texture3);

                  texture4 = new Texture(arrayBitmap[3]);
                  texture4.setMipmap(false);
                  texture4.compress();
                  TextureManager.getInstance().addTexture("texture4",
                        texture4);

                  Log.i("Textures", "added");
                  finCtrl = 1;
                  loadSphere();

               } else {
                  Log.d("BÄ°TMAP NULL Mı?", "NULL");
               }

            }
         });

         /*
          * AsynImageDownloader asynImg = new AsynImageDownloader(path, new
          * AsynImageEvent.ImageEvent() {
          *
          * @Override public void onComplete(InputStream insP) {
          *
          * BitmapFactory.Options opts = new BitmapFactory.Options();
          * opts.inSampleSize = 1; Bitmap bm =
          * BitmapFactory.decodeStream(insP, null, opts); texture = new
          * Texture(bm); texture.setMipmap(false);
          * TextureManager.getInstance().replaceTexture("texture", texture);
          *
          * Log.d("SEVENE CANIM FEDA", " ELVEDA"); } });
          *
          *
          * asynImg.execute((Void[]) null);
          *
          * /* BitmapFactory.Options opts = new BitmapFactory.Options();
          * opts.inSampleSize = 1; Bitmap bm =
          * BitmapFactory.decodeStream(insP, null, opts); texture = new
          * Texture(bm); texture.setMipmap(false);
          *
          *
          * Log.d("RESÄ°M NEREDE LOOOOOO " , " OLMD");
          * //mainSphere.setTexture("texture");
          */
         // Log.v("Oldu","oldu");

      } catch (Exception e) {
         Log.d("Hata!", "var");
         e.printStackTrace();
      }

   }

   public void setCurrentJSONData(ArrayList<JSONDatas> jsonData) {
      setCurrentPanaromicData(jsonData.get(0));

      arrowMan.addArrows(jsonData);

   }
}

Log

Quote
01-16 09:07:45.675: I/dalvikvm-heap(1923): Grow heap (frag case) to 46.806MB for 8388620-byte allocation
01-16 09:07:45.687: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 11% free 46879K/52551K, paused 12ms+0ms, total 15ms
01-16 09:07:45.691: D/dalvikvm(1923): GC_FOR_ALLOC freed 0K, 11% free 46879K/52551K, paused 2ms, total 2ms
01-16 09:07:45.703: I/dalvikvm-heap(1923): Grow heap (frag case) to 54.806MB for 8388620-byte allocation
01-16 09:07:45.715: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 10% free 55071K/60807K, paused 10ms+0ms, total 14ms
01-16 09:07:45.851: D/dalvikvm(1923): GC_FOR_ALLOC freed 8610K, 24% free 46460K/60807K, paused 2ms, total 2ms
01-16 09:07:45.851: I/dalvikvm-heap(1923): Grow heap (frag case) to 54.398MB for 8388620-byte allocation
01-16 09:07:45.867: D/dalvikvm(1923): GC_CONCURRENT freed <1K, 11% free 54652K/60807K, paused 11ms+1ms, total 14ms
01-16 09:07:45.871: D/dalvikvm(1923): GC_FOR_ALLOC freed 8192K, 24% free 46460K/60807K, paused 3ms, total 3ms
01-16 09:07:45.871: I/dalvikvm-heap(1923): Grow heap (frag case) to 54.398MB for 8388620-byte allocation
01-16 09:07:45.883: D/dalvikvm(1923): GC_CONCURRENT freed <1K, 11% free 54652K/60807K, paused 10ms+1ms, total 13ms
01-16 09:07:46.047: I/jPCT-AE(1923): Creating buffers...
01-16 09:07:46.147: I/jPCT-AE(1923): VBO created for object 's4_jPCT0'
01-16 09:07:46.147: W/jPCT-AE(1923): [ 1421399266151 ] - WARNING: Texture's size is 1024/2048, but textures should be square for OpenGL ES2.0! This may result in a black texture!
01-16 09:07:46.159: D/dalvikvm(1923): GC_FOR_ALLOC freed 25108K, 50% free 30631K/60807K, paused 4ms, total 4ms
01-16 09:07:46.167: D/dalvikvm(1923): GC_FOR_ALLOC freed 553K, 49% free 31184K/60807K, paused 3ms, total 3ms
01-16 09:07:46.167: I/dalvikvm-heap(1923): Grow heap (frag case) to 33.642MB for 2267142-byte allocation
01-16 09:07:46.183: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 46% free 33398K/60807K, paused 11ms+2ms, total 14ms
01-16 09:07:46.195: D/dalvikvm(1923): GC_FOR_ALLOC freed 1106K, 47% free 32292K/60807K, paused 2ms, total 2ms
01-16 09:07:46.195: I/dalvikvm-heap(1923): Grow heap (frag case) to 36.886MB for 4535416-byte allocation
01-16 09:07:46.207: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 40% free 36721K/60807K, paused 11ms+1ms, total 13ms
01-16 09:07:46.239: D/dalvikvm(1923): GC_FOR_ALLOC freed 2214K, 44% free 34507K/60807K, paused 4ms, total 4ms
01-16 09:07:46.239: I/dalvikvm-heap(1923): Grow heap (frag case) to 43.376MB for 9072552-byte allocation
01-16 09:07:46.255: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 29% free 43367K/60807K, paused 10ms+1ms, total 13ms
01-16 09:07:46.287: D/dalvikvm(1923): GC_FOR_ALLOC freed 4429K, 36% free 38937K/60807K, paused 4ms, total 4ms
01-16 09:07:46.287: I/dalvikvm-heap(1923): Grow heap (frag case) to 47.051MB for 8388620-byte allocation
01-16 09:07:46.303: D/dalvikvm(1923): GC_CONCURRENT freed 0K, 23% free 47129K/60807K, paused 12ms+0ms, total 14ms
01-16 09:07:46.307: D/dalvikvm(1923): GC_FOR_ALLOC freed 0K, 23% free 47129K/60807K, paused 2ms, total 2ms
01-16 09:07:46.307: I/dalvikvm-heap(1923): Forcing collection of SoftReferences for 8388620-byte allocation
01-16 09:07:46.311: D/dalvikvm(1923): GC_BEFORE_OOM freed 0K, 23% free 47129K/60807K, paused 4ms, total 4ms
01-16 09:07:46.311: E/dalvikvm-heap(1923): Out of memory on a 8388620-byte allocation.
01-16 09:07:46.311: I/dalvikvm(1923): "GLThread 158" prio=5 tid=10 RUNNABLE
01-16 09:07:46.311: I/dalvikvm(1923):   | group="main" sCount=0 dsCount=0 obj=0xa6927768 self=0xb8077a98
01-16 09:07:46.311: I/dalvikvm(1923):   | sysTid=1935 nice=0 sched=0/0 cgrp=[fopen-error:2] handle=-1206534120
01-16 09:07:46.311: I/dalvikvm(1923):   | schedstat=( 816015834 247673968 3020 ) utm=69 stm=12 core=0
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.ZipHelper.byteArrayToInt(ZipHelper.java:~115)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.ZipHelper.unzip(ZipHelper.java:47)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.GLRenderer.convertTexture(GLRenderer.java:877)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.GLRenderer.setTextures(GLRenderer.java:2448)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.GLRenderer.drawVertexArray(GLRenderer.java:2297)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.World.draw(World.java:1417)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.threed.jpct.World.draw(World.java:1100)
01-16 09:07:46.311: I/dalvikvm(1923):   at com.example.jcptlib.MyRenderer.onDrawFrame(MyRenderer.java:298)
01-16 09:07:46.311: I/dalvikvm(1923):   at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
01-16 09:07:46.311: I/dalvikvm(1923):   at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
01-16 09:07:46.319: W/dalvikvm(1923): threadid=10: thread exiting with uncaught exception (group=0xa622c288)
01-16 09:07:46.319: E/AndroidRuntime(1923): FATAL EXCEPTION: GLThread 158
01-16 09:07:46.319: E/AndroidRuntime(1923): java.lang.OutOfMemoryError
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.ZipHelper.byteArrayToInt(ZipHelper.java:115)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.ZipHelper.unzip(ZipHelper.java:47)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.GLRenderer.convertTexture(GLRenderer.java:877)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.GLRenderer.setTextures(GLRenderer.java:2448)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.GLRenderer.drawVertexArray(GLRenderer.java:2297)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.World.draw(World.java:1417)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.threed.jpct.World.draw(World.java:1100)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at com.example.jcptlib.MyRenderer.onDrawFrame(MyRenderer.java:298)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516)
01-16 09:07:46.319: E/AndroidRuntime(1923):    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
01-16 09:07:46.879: D/OpenGLRenderer(1923): TextureCache::flush: target size: 639129
01-16 09:07:46.879: D/OpenGLRenderer(1923): TextureCache::callback: name, removed size, mSize = 1, 1048576, 16640


EgonOlsen

That's simple: You run out of memory. Keep in mind that a 2048*1024 texture requires 8MB for each image in main memory, 8MB on the gpu and up to 8mb (depending on the compression rate) for the zipped data. Plus mipmaps and additional stuff that your app requires. Keep in mind that you are on a mobile device and that, all progress aside, this is still an environment with limited resources.
The amount of memory available to the VM depends on the Android version and some vendor settings. In your case, it seems to be 64mb, which indicates that this is a rather old device/Android version. You can try to set the largeHeap setting in your manifest (http://developer.android.com/guide/topics/manifest/application-element.html), but that doesn't always help. It's better to watch your content. Do you REALLY need 4 textures of that enormous size?

suheyb1991

#2
Thanks Egon. largeheap=true works.

EgonOlsen

Just keep in mind that it's up to the vendor what this switch actually does. They are free to ignore it (albeit i've never come across this...).

gamenewer

Hello , I meet this case too, If  add more texture , the memory sieze > 32 M ,the OOM is occurs. I am wonder  If  use native method to decode the picture and  let  bitmap reference  to native memory, maybe can resove  OOM, but I don't know this way can do this or not .

EgonOlsen

Personally, i haven't seen a device/VM with just 32mb since Android 1.6. Current devices provide 256 or 512 without any problems. Native memory will be counted as memory of the process too. That's why the native memory in which the textures reside when you move them onto the gpu counts as well.
If your app throws an OOM, you are simply using too much memory. Try to lower that and also define a minimum amount of memory that your app should be able to work with and develop with that barrier in mind. IMHO, something like a 2048*1024 texture shouldn't be used on a mobile device except for some very special cases. Apart from that, here are some hints regarding memory usage and reduction: http://www.jpct.net/wiki/index.php/Reducing_memory_usage

EgonOlsen

As an example: My RPG ( https://www.youtube.com/watch?v=bJf2B3tlg5Y ) uses one 512*512 texture. All other textures are smaller. It uses one 1000*1000 heightmap, 18 different animated meshes for NPCs and enemies, dozens of other meshes, 64 sounds and 3 songs and it all fits into 64mb of memory by using some of the hints mentioned on that wiki page.