maxPolysVisible Memory Leak

Started by dear_stephen, June 15, 2007, 01:30:54 PM

Previous topic - Next topic

dear_stephen

Hi

I am using normal sampling when the mouse is down and oversampling when the mouse is pressed.

When recreating the FrameBuffer often I get a memory leak if and only if I use the following line...

Config.maxPolysVisible = 64000;






a "minimal" example...

package com.algodes.jpct;

import java.applet.Applet;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

public class TestApplet extends Applet implements MouseListener, Runnable{
FrameBuffer buffer;
World world;
Thread loopThread;
boolean exit = false;
public TestApplet(){
addMouseListener(this);
buffer = changeSampleMode(FrameBuffer.SAMPLINGMODE_NORMAL);

// comment this out to get rid of the memory leak.
Config.maxPolysVisible = 64000;
}
public void run() {
world = new World();
Object3D root = Object3D.createDummyObj();
root.setName("root");
world.addObject(root);
addContent();
setCamera();

while(!exit){
buffer.clear(Color.WHITE);
synchronized (world) {
world.renderScene(buffer);
world.draw(buffer);
buffer.display(getGraphics());
}
buffer.update();
}
}
protected void addContent() {
// world.removeAll();
Object3D obj = Primitives.getBox(10, 10);
Object3D root = world.getObjectByName("root");

world.addObject(obj);

root.addChild(obj);

world.buildAllObjects();
world.addLight(new SimpleVector(150, 150, -450), 95, 95, 95);
world.setAmbientLight(220, 220, 220);
}

public void start() {
System.out.println("Initializing threads!");
if (loopThread == null) {
loopThread = new Thread(this);
loopThread.start();
}
}


public void destroy() {
System.out.println("destroy applet");
// Object3D.resetObjCount();
exit = true;
super.destroy();
}
private FrameBuffer changeSampleMode(int mode){
// memory leak
buffer = new FrameBuffer(550, 550, mode);
return buffer;
}

public void mouseClicked(MouseEvent event) {
changeSampleMode(FrameBuffer.SAMPLINGMODE_NORMAL);
}
public void mousePressed(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}

public void mouseReleased(MouseEvent event) {
changeSampleMode(FrameBuffer.SAMPLINGMODE_OGSS);
}
public void keyTyped(KeyEvent e) {
}


protected void setCamera() {
SimpleVector cameraPosition = new SimpleVector(0, 0, 0);
// cameraPosition = product.getCenter();
cameraPosition.z = cameraPosition.z + 500;
Camera camera = world.getCamera();
camera.setPosition(cameraPosition);
// SimpleVector center = product.getCenter();
SimpleVector center = new SimpleVector(0, 0, 0);

camera.lookAt(center);
camera.setFOV(1.0f);
}

}



cheers,
Stephen

EgonOlsen

FrameBuffer has a dispose()-method that should be called before forgetting the old reference. Try and see if that helps.

dear_stephen

Hi

I added ...

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


... before ...


buffer = new FrameBuffer(550, 550, mode);


but unfortunately it didn't help. With Config.maxPolysVisible = 8192; I also got the problem.




halcor

Possible workaround: use 2 framebuffers and decide in which one to render and display.

EgonOlsen

I can't verify the problem with the given code. I can happily switch between sampling modes and visibility lists get disposed (if not by calling dispose(), there'll automatically getting disposed in FrameBuffer's finalize()).
I've tested this in an application, so i guess the problem is related to the applet's 64MB limit which may not allow two framebuffers to exist at a time. You may try to replace the

buffer.dispose();
buffer=new FrameBuffer(...);


with


buffer.dispose();
buffer=null;
buffer=new FrameBuffer(...);


Looks similar, but it isn't, because the VM discards the reference to the old buffer AFTER instanciating the new one. By setting it to null before, you help the gc to collect it ealier if needed. However, you are doing these calls in the event thread, which is not a good idea, because you are mixing buffer access in the main loop with buffer creation in the event. Those parts should at least by synchronized to world in this code.

dear_stephen

Adding...


  buffer = null;


... did the trick.

Thanks very much!