Strange garbage collector behavior

Just noticed a thing about java’s garbage collector.



Example 1:

[java]

public class Sprite

{

private Vector3f position = Vector3f.Zero; //yay fast constructor.

}



simpleUpdate()

{

sprite.position = new Vector3f( random, random, random );

}

[/java]



The fps will drop each time, e.g from 190 fps to 90 fps after a lot of time.

Example 2:

[java]

public class Sprite

{

private Vector3f position = new Vector3f();

}



simpleUpdate()

{

sprite.position.set (new Vector3f( random, random, random ));

}

[/java]



Stable fps at 190 fps because java hotspot automatically optimizes it.



Calling system.gc(); will fix it example1 temporary, but it is a slow operation.



Lesson of the day: optimizations can hurt you in the end.

If you use it the same way as you would a temp vector you can save the time of object creation on each update.



[java]

public class Sprite

{

private Vector3f position = new Vector3f();

}



simpleUpdate()

{

sprite.position.x=random;

sprite.position.y=random;

sprite.position.z=random;

}

[/java]

yes but java hotspot automatically inlines them. proof: same fps.

Which version/update of Java are you using ?

Have you tried with Java 7 ?



Are you accessing a private attribute from outside the class ? :smiley:

The issue is with the lifetime of the objects. In example one you basically wait one frame until you release the new object. In example two the only new object is released in what would be the stack in C which is essentially free in java as the gc is tuned for these. So this isn’t really strange but expected and a good example on how this can impact your application.

Ok, after more testing, i am starting to think the problem was in another part of the program.



a) First of all the buffers i allocate for my sprites are never garbage collected.



[java]

import com.jme3.app.SimpleApplication;

import com.jme3.util.BufferUtils;

import java.nio.FloatBuffer;



public class TestJmeBufferBug extends SimpleApplication

{

public static void main(String[] args)

{

new TestJmeBufferBug().start();

}



@Override

public void simpleInitApp()

{

}



@Override

public void simpleUpdate(float tpf)

{

super.simpleUpdate(tpf);

FloatBuffer fb = BufferUtils.createFloatBuffer(30000);

}

}

[/java]



After a few seconds i get :

java.lang.OutOfMemoryError

at sun.misc.Unsafe.allocateMemory(Native Method)

at java.nio.DirectByteBuffer.(DirectByteBuffer.java:126)

at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)

at com.jme3.util.BufferUtils.createFloatBuffer(BufferUtils.java:783)

at tests.sprite.junk.TestJmeBufferBug.simpleUpdate(TestJmeBufferBug.java:24)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:149)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:182)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:223)

at java.lang.Thread.run(Thread.java:722)



Is there no way in jme to de-allocate a buffer?



b) Also this somehow expains why the above bug happened.

b1) if we wanted to test which approach is faster, we will have to create a new benchmark test.

Direct buffers are different in java, we had many discussions about this topic, try TestReleaseDirectMemory for a possible way to release them. The issue with them is they do not trigger a GC but get cleaned when a GC runs, so making your java heap small in comparison to the direct memory heap will assure gc runs often enough.

i tried System.gc(); it works, although i don’t thing i am gonna use it in my application because calling it every frame will reduce the fps to 25.



About TestReleaseDirectMemory, it works nice and it is very fast, is there a reason we don’t have a method to destroy other types of buffers e.g FloatBuffer ?

System.gc() is the worst you can do. It basically stops everything, all threads, all execution.

As long as the buffer is referenced, it won’t be garbage collected. You can try to force your variable to null, but the garbage collector will still need some free time to release the buffers, if you allocate them too quickly, you will saturate your memory beforehand and crash



Why do you allocate so many buffers ? It shouldn’t be necessary…

I tried creating one buffer with big capacity so that i wont need to reconstruct it every frame.

I set the limit so that it would stop reading beyond the sprite data.

However jme reads beyond buffer.limit, it reads until end of capacity is reached.



Right now, lets say i have 1 sprite on screen and a buffer with 10000 capacity,

to solve this bug i render 9999 sprites at Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); which means that the speed of application is limited by the buffer capacity.

oO whaaayayaysia? whats it you want to achieve?

http://www.youtube.com/watch?v=wVBiRqKj6j8