OutOfMemoryError on ICS

Started by Thomas., November 30, 2011, 11:16:57 AM

Previous topic - Next topic

Thomas.

Application crashes during the loading with this error log. On gingerbread without any problem.

11-30 11:09:33.691: W/dalvikvm(21679): threadid=14: thread exiting with uncaught exception (group=0x40a321f8)
11-30 11:09:33.695: E/AndroidRuntime(21679): FATAL EXCEPTION: Thread-7392
11-30 11:09:33.695: E/AndroidRuntime(21679): java.lang.OutOfMemoryError
11-30 11:09:33.695: E/AndroidRuntime(21679): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
11-30 11:09:33.695: E/AndroidRuntime(21679): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:493)
11-30 11:09:33.695: E/AndroidRuntime(21679): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:549)
11-30 11:09:33.695: E/AndroidRuntime(21679): at com.threed.jpct.util.BitmapHelper.loadImage(BitmapHelper.java:32)
11-30 11:09:33.695: E/AndroidRuntime(21679): at com.threed.jpct.Texture.loadTexture(Texture.java:715)
11-30 11:09:33.695: E/AndroidRuntime(21679): at com.threed.jpct.Texture.loadTexture(Texture.java:703)
11-30 11:09:33.695: E/AndroidRuntime(21679): at com.threed.jpct.Texture.<init>(Texture.java:135)
11-30 11:09:33.695: E/AndroidRuntime(21679): at cz.game.util.ObjectLoader.loadValuesOfObjects(ObjectLoader.java:471)
11-30 11:09:33.695: E/AndroidRuntime(21679): at cz.game.util.ObjectLoader.loadLevel(ObjectLoader.java:314)
11-30 11:09:33.695: E/AndroidRuntime(21679): at cz.game.util.ObjectLoader.load(ObjectLoader.java:203)
11-30 11:09:33.695: E/AndroidRuntime(21679): at cz.game.util.ObjectLoader.run(ObjectLoader.java:116)
11-30 11:09:33.703: W/ActivityManager(188):   Force finishing activity com.main/cz.game.main.Demo

EgonOlsen

No idea. I'm not doing anything OS related anywhere in the code. Maybe this relates to this: http://www.jpct.net/forum2/index.php/topic,2429.0.html?

Edit: What's the default VM memory size on that device? Maybe it's lower than on the Gingerbread device...

K24A3

I have the same problem with Honeycomb. For some reason the app uses double the RAM compared to Gingerbread. You can use the new LargeHeap parameter in Android.Manifest to increase the RAM to 256MB but you will lose Gingerbread compatibility.

Use this function to see how much RAM is used in both gingerbread and ICS:


public void logMem() {
        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(0);
        df.setMinimumFractionDigits(0);

        String sTemp = "RAM allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)";
        Log.v(TAG, sTemp);
    }

Thomas.

I think that on gingerbread was VM memory size 48Mb and now on ICS it is 32Mb... how can I reduce demands on this memory?
K24A3:
11-30 12:24:57.277: I/jPCT-AE(22387): RAM allocated: 31MB of 32MB (0MB free)
11-30 12:24:57.414: I/dalvikvm-heap(22387): Clamp target GC heap from 32.692MB to 32.000MB
11-30 12:24:57.605: E/AndroidRuntime(22387): FATAL EXCEPTION: GLThread 7473
...


K24A3

I believe the manufacturer of the phone/tablet can set the max VM size so perhaps that is why it's only 32MB.

EgonOlsen

Yes, it's not an OS issue. It can be set by the manufacturer. Even 32mb is pretty much compared to others. My Nexus S has 24mb IIRC and my old Galaxy (no S) has 16.

Alexey

Not about ICS, but about memory - when i create for example 200 objects (by cloning primitive.sphere(4,1) , without any texture) i have

12-01 16:08:15.743: ERROR/dalvikvm-heap(29270): 768-byte external allocation too large for this process.
12-01 16:08:15.743: ERROR/dalvikvm(29270): Out of memory: Heap Size=23399KB, Allocated=8825KB, Bitmap Size=943KB, Limit=21884KB
12-01 16:08:15.743: ERROR/dalvikvm(29270): Trim info: Footprint=23879KB, Allowed Footprint=23879KB, Trimmed=480KB
12-01 16:08:15.743: WARN/OSMemory(29270): External allocation of 768 bytes was rejected
12-01 16:08:15.753: WARN/dalvikvm(29270): threadid=8: thread exiting with uncaught exception (group=0x40025a70)
12-01 16:08:15.773: ERROR/AndroidRuntime(29270): FATAL EXCEPTION: GLThread 9
        java.lang.OutOfMemoryError
        at org.apache.harmony.luni.platform.OSMemory.malloc(Native Method)
        at org.apache.harmony.luni.platform.PlatformAddressFactory.alloc(PlatformAddressFactory.java:150)
        at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:66)
        at java.nio.ReadWriteDirectByteBuffer.<init>(ReadWriteDirectByteBuffer.java:51)
        at java.nio.BufferFactory.newDirectByteBuffer(BufferFactory.java:93)
        at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:68)
        at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:774)
        at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:151)
        at com.threed.jpct.World.compile(World.java:2050)
        at com.threed.jpct.World.renderScene(World.java:1093)


Is that really out of memory or i have some memory leak ? (desire hd)

EgonOlsen

I don't know if you have a memory leak, but it might very well be an OOM. Unless you are sharing Mesh and compiled data, each instance needs it's own chunk of memory even if they are actually the same objects. Again, consider: http://www.jpct.net/wiki/index.php/Reducing_memory_usage, especially the 1.4.x parts.

Alexey

i tried cloneObject() & new Object3d(o, reuseMesh=true). Tried primitive.shareCompiledData(each cloned object).
Creation part:

Object3D original = Primitives.getSphere(4, 1);
original.compile();
original.strip();
original.build();
original.rotateY((float) (Math.PI / 4));
short i = 0;
short y = 0;
short z = 0;
short rowCount = 0;
for (int j = 0; j < particles.length; j++) {
ParticlePB particle = new ParticlePB();
Object3D o =  new Object3D(original, true);//box.cloneObject();
if (i == inRow) {
i = 0;
++rowCount;
}
original.shareCompiledData(o);
o.strip();
// o.forceGeometryIndices(true);
o.build();
y = (short) (i * moveStep);
z = (short) (rowCount * moveStep);
o.translate(0, y, z);
++i;
particle.setObject3D(o);
particles[j] = particle;
world.addObject(o);
System.out.println(usedMemory());
}

after create each SOUT write:

12-01 18:05:48.775: INFO/System.out(29877): 7857992
12-01 18:05:48.775: INFO/System.out(29877): 7870520
12-01 18:05:48.775: INFO/System.out(29877): 7885464
12-01 18:05:48.775: INFO/System.out(29877): 7898184
12-01 18:05:48.775: INFO/jPCT-AE(29877): Memory usage before compacting: 7714 KB used out of 23399 KB

So each obj ~12k, count of iteration = 500;
after that log write sequence

2-01 18:05:49.495: INFO/jPCT-AE(29877): Subobject of object 5/object7 compiled to flat fixed point data using 96 vertices in 5ms!
12-01 18:05:49.495: INFO/jPCT-AE(29877): Object 5/object7 compiled to 1 subobjects in 12ms!
12-01 18:05:49.495: INFO/jPCT-AE(29877): Object 'object7' uses one texture set!
12-01 18:05:49.495: INFO/jPCT-AE(29877): Subobject of object 6/object8 compiled to flat fixed point data using 96 vertices in 1ms!
12-01 18:05:49.505: INFO/jPCT-AE(29877): Object 6/object8 compiled to 1 subobjects in 8ms!
12-01 18:05:49.505: INFO/jPCT-AE(29877): Object 'object8' uses one texture set!
...
12-01 18:05:50.515: INFO/jPCT-AE(29877): Subobject of object 310/object312 compiled to flat fixed point data using 96 vertices in 1ms!
12-01 18:05:50.515: INFO/jPCT-AE(29877): Object 310/object312 compiled to 1 subobjects in 3ms!
12-01 18:05:50.515: INFO/jPCT-AE(29877): Object 'object312' uses one texture set!
12-01 18:05:50.515: ERROR/dalvikvm-heap(29877): 768-byte external allocation too large for this process.
12-01 18:05:50.515: ERROR/dalvikvm(29877): Out of memory: Heap Size=23399KB, Allocated=8826KB, Bitmap Size=943KB, Limit=21884KB
12-01 18:05:50.515: ERROR/dalvikvm(29877): Trim info: Footprint=23879KB, Allowed Footprint=23879KB, Trimmed=480KB
12-01 18:05:50.515: WARN/OSMemory(29877): External allocation of 768 bytes was rejected
12-01 18:05:50.525: WARN/dalvikvm(29877): threadid=8: thread exiting with uncaught exception (group=0x40025a70)
12-01 18:05:50.535: ERROR/AndroidRuntime(29877): FATAL EXCEPTION: GLThread 9
        java.lang.OutOfMemoryError
        at org.apache.harmony.luni.platform.OSMemory.malloc(Native Method)
        at org.apache.harmony.luni.platform.PlatformAddressFactory.alloc(PlatformAddressFactory.java:150)
        at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:66)
        at java.nio.ReadWriteDirectByteBuffer.<init>(ReadWriteDirectByteBuffer.java:51)
        at java.nio.BufferFactory.newDirectByteBuffer(BufferFactory.java:93)
        at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:68)
        at com.threed.jpct.CompiledInstance.fill(CompiledInstance.java:774)
        at com.threed.jpct.Object3DCompiler.compile(Object3DCompiler.java:151)
        at com.threed.jpct.World.compile(World.java:2050)
        at com.threed.jpct.World.renderScene(World.java:1093)


There are only this objects in world. I think they should not overflow the memory.
What doing when out like "INFO/jPCT-AE(29877): Subobject of object 5/object7 compiled to flat fixed point data using 96 vertices in 5ms!
12-01 18:05:49.495: INFO/jPCT-AE(29877): Object 5/object7 compiled to 1 subobjects in 12ms!" ?

EgonOlsen

This

original.shareCompiledData(o);

is wrong. It has to be the other way round

o.shareCompiledData(original);

The log output that you see is when it converts the Object3Ds into native data structures, which takes some additional memory.

Alexey

Quote from: EgonOlsen on December 01, 2011, 08:32:37 PM
o.shareCompiledData(original);
Yes! Thats it! Thank you! With this data sharing i run 3000 objects  without OOM.
Another question  - if objects convert to native data (as i know, native memory usage  not included to activity memory usage) they should not contribute to the overflow activity memory limit if load its by parts then convert loaded part to native data and clear their mesh data in java object3d (of course this only for static meshes). If sometime will be need to load ~many hard-weight static objects without sharing compile data, is it possible to realize some like this loading process? Is there a way to force convert obj to native data and safety set null its mesh data? (and same for textures)

EgonOlsen

Native memory counts to the VM memory as well. There are hacks around this, but not if you reserve the memory via the VM. strip() already nulls what can be nulled after uploading to the GPU. The rest of the data is needed by the engine at runtime. Concerning textures, you can disable the copy in main memory...but that will break the option to let jPCT manage context switches for you, i.e. if you pause/stop or just rotate the device, the gl context is lost and all the data has to be uploaded again. jPCT handles this for you, but if you remore the texture from main memory, this isn't possible and everything will go white instead. You can't do the conversion earlier (i.e. at load time), because it has to happen in the render thread.