Author Topic: Replacing a texture leads to (Native memory leak)  (Read 7203 times)

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Replacing a texture leads to (Native memory leak)
« on: February 07, 2015, 07:51:06 pm »
So I have a texture that is sometimes replaced, but it seems to leak Native memory (Non heap).

I do the following

1) unload texture
2) New texture
3) Replace texture
4) Buffer.display

Is this wrong ?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #1 on: February 07, 2015, 10:24:05 pm »
Should be fine unless you render some object that uses the unloaded texture in between. This can happen when using a multi-threaded renderer like the AWTGLRenderer or the multithreading option of the normal renderer. In that case, try to synchronize the whole texture replacement code on the lock object that you can obtain from the FrameBuffer.
What exactly makes you think that you are losing native memory?

BTW: You can set the Logger to debug and Config.glVerbose to true to keep track of texture up- and unloading, if that helps.


Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #2 on: February 08, 2015, 12:18:42 pm »
We are using the AWTGLRenderer, so that might explain it, but I am doing this in the rendering loop, so was hoping everything was synchronized allready.

I can see that I am leaking handles and my virtual memory skyrockets, after 1 hour of running I am using 6GB after 1,5 12GB and then the systems stops completely.

I'll try the FrameBuffer.synchronization and the Config.glVerbose.

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #3 on: February 08, 2015, 01:38:31 pm »
I get this
Allocating 4194304 bytes of direct memory for texture: com.threed.jpct.Texture@25bbf0b7
Creating new disposable buffer of size 4194304
Caching 4194304 bytes of direct memory!

But nothing about unloading a texture

this is the code
Code: [Select]
        _textureManager.unloadTexture(_buffer, _elementsTexture);

        _elementsTexture = new Texture(_elementsImage);
        _elementsTexture.setMipmap(false);
        _elementsTexture.setGLFiltering(false);

        _textureManager.replaceTexture(ELEMENTS_TEXTURENAME, _elementsTexture);

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #4 on: February 08, 2015, 04:18:43 pm »
But that's not the complete log or is it? It doesn't contain anything about uploading the new texture either. Both should happen during the next render pass.

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #5 on: February 08, 2015, 05:27:05 pm »
But that's not the complete log or is it? It doesn't contain anything about uploading the new texture either. Both should happen during the next render pass.

This is all I get when changing the Texture

Allocating 4194304 bytes of direct memory for texture: com.threed.jpct.Texture@27174693
Creating new disposable buffer of size 4194304
Caching 4194304 bytes of direct memory!
updateElementsTexture <- My own log
Loading Texture...from Image


Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #6 on: February 08, 2015, 05:56:47 pm »
Forgot

Code: [Select]
Logger.setLogLevel(Logger.LL_VERBOSE);

But still this is what I get

Code: [Select]
updateElementsTexture
Loading Texture...from Image
Allocating 4194304 bytes of direct memory for texture: com.threed.jpct.Texture@32cb56e6
Caching 4194304 bytes of direct memory!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #7 on: February 08, 2015, 05:59:43 pm »
I'll create my own test case and see what happens. I'm not sure how upload plays together with replace...i'll report back.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #8 on: February 08, 2015, 06:35:04 pm »
BTW: Log level should  be debug, not just verbose.

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #9 on: February 08, 2015, 06:40:35 pm »
BTW: Log level should  be debug, not just verbose.

Tried with both, wasn't sure which was most important

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #10 on: February 08, 2015, 08:05:56 pm »
I think i can reproduce the issue...i'm just not sure what causes it. Looks like as if the unload operation never happens. The log output is sparse as you've already mentioned. I thought that it's on par with jPCT-AE, which is much more verbose in debug mode, but obviously it isn't. I'll add more logging while i'm on it and report back later...

BTW: It works as expected with the native GL renderer, so it has something to do with AWT renderer's multithreaded nature... ???
« Last Edit: February 08, 2015, 08:15:45 pm by EgonOlsen »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #11 on: February 08, 2015, 08:39:47 pm »
Well, actually it's all fine...my test case was just ignoring the fact that the draw loop executes in parallel to the rendering thread, so you can in theory stuff thousands of new and never used textures into the unload-queue before the first render pass is able to dispose them all. Once i handled this, it behaved as expected. However, i'm not sure if there isn't some similar side-effect in your case, so i suggest to try what i did in this test case: Move the texture replacement stuff into the finishedPainting()-method of an IPaintListener implementation. Have a look here:

Code: [Select]
import java.awt.Canvas;
import java.awt.Color;
import java.util.Random;

import javax.swing.JFrame;

import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IPaintListener;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;

public class TextureModTest implements IPaintListener {

private static final long serialVersionUID = 1L;

private Random rnd = new Random();

private int cnt = 0;

private World world;

private FrameBuffer buffer;

private Object3D box;

private Texture boxTex;

private JFrame frame;

public static void main(String[] args) throws Exception {
new TextureModTest().loop();
}

public TextureModTest() throws Exception {

Logger.setOnError(Logger.ON_ERROR_THROW_EXCEPTION);
Logger.setLogLevel(Logger.LL_DEBUG);
Config.glVerbose = true;

frame = new JFrame("Hello world");
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

world = new World();
world.setAmbientLight(0, 255, 0);

boxTex = new Texture("box.jpg");
TextureManager.getInstance().addTexture("box", boxTex);

box = Primitives.getBox(13f, 2f);
box.setTexture("box");
box.setEnvmapped(Object3D.ENVMAP_ENABLED);
box.build();
box.compile();
world.addObject(box);

world.getCamera().setPosition(50, -50, -5);
world.getCamera().lookAt(box.getTransformedCenter());
}

private void loop() throws Exception {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_GL_AA_4X);
Canvas canvas = buffer.enableGLCanvasRenderer();
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
frame.add(canvas);

buffer.setPaintListener(this);

while (frame.isShowing()) {
box.rotateY(0.01f);
buffer.clear(java.awt.Color.BLUE);
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
canvas.repaint();
}

System.exit(0);
}

@Override
public void startPainting() {
// TODO Auto-generated method stub
}

@Override
public void finishedPainting() {
TextureManager.getInstance().unloadTexture(buffer, boxTex);
boxTex = new Texture(256, 256, new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256)));
TextureManager.getInstance().replaceTexture("box", boxTex);
System.out.println("Iteration: " + cnt++ + "/" + Runtime.getRuntime().maxMemory() + "/" + Runtime.getRuntime().freeMemory());
}
}

Apart from that, i've uploaded a new beta jar with better debug logging. If the IPaintListener stuff doesn't help, maybe this will help to track down the problem: http://jpct.de/download/beta/jpct.jar

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #12 on: February 08, 2015, 09:50:27 pm »
Ok, the logs helped a bit, but I cannot figure out what is wrong.

It seems that whenever i replace the texture the old texture is uploaded as well as the new one.

So the leak is that both the old and the new texture exists ... or something.

Using the taskmanager I can see the handle count increate whenever i replace the texture

Code: [Select]
Texture 2 added for unloading (1)!
Loading Texture...from Image
Textures to unload: 1
Unloading texture 2
texture 2 unloaded from GPU memory!
Allocating 4194304 bytes of direct memory for texture: com.threed.jpct.Texture@76ce21e7
Creating new disposable buffer of size 4194304
Caching 4194304 bytes of direct memory!
New texture's id is: 2
New texture uploaded: com.threed.jpct.Texture@76ce21e7 in thread Thread[AWT-EventQueue-0,6,main]
New texture's id is: 6
New texture uploaded: com.threed.jpct.Texture@51a3adb in thread Thread[AWT-EventQueue-0,6,main]
updateElementsTexture
Texture 6 added for unloading (1)!
Loading Texture...from Image
Textures to unload: 1
Unloading texture 6
texture 6 unloaded from GPU memory!
New texture's id is: 6
New texture uploaded: com.threed.jpct.Texture@51a3adb in thread Thread[AWT-EventQueue-0,6,main]
New texture's id is: 7
New texture uploaded: com.threed.jpct.Texture@66c9cfd2 in thread Thread[AWT-EventQueue-0,6,main]
« Last Edit: February 08, 2015, 09:53:33 pm by Mr_Chaos »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Replacing a texture leads to (Native memory leak)
« Reply #13 on: February 08, 2015, 09:58:44 pm »
I'm not sure what i'm seeing there. It somehow looks as if the unloaded texture will be uploaded again right afterwards, but i'm not entirely sure. Can you add some logging on your side so that we can keep track of which texture should actually be unloaded and which one is the replacement texture? It should be sufficient to output the Texture instance itself, so that we can simply compare the memory addresses of those with the ones logged by the renderer.
« Last Edit: February 08, 2015, 10:01:57 pm by EgonOlsen »

Offline Mr_Chaos

  • int
  • **
  • Posts: 57
    • View Profile
Re: Replacing a texture leads to (Native memory leak)
« Reply #14 on: February 09, 2015, 09:55:37 am »
Ok, by changing it to use the IPaintListener the logs look a lot better, the problem is that I still have a handle leak.

I am using a BufferedImage to create the texture from, don't know if that might be a problem ?

Code: [Select]
********************updateElementsTexture********************
oldTexture=<com.threed.jpct.Texture@24fa5c93>
Texture 2 added for unloading (1)!
Loading Texture...from Image
newTexture=<com.threed.jpct.Texture@324895c0>
********************updateElementsTexture********************
Textures to unload: 1
Unloading texture 2
texture 2 unloaded from GPU memory!
New texture's id is: 2
New texture uploaded: com.threed.jpct.Texture@324895c0 in thread Thread[AWT-EventQueue-0,6,main]