Java3D离屏渲染内存泄漏

时间:2012-12-03 09:41:59

标签: java memory-leaks rendering java-3d off-screen

为了保存我的3D画布的快照,我在下一步扩展了Canvas3D

class OffScreenCanvas3D extends Canvas3D {
    OffScreenCanvas3D(GraphicsConfiguration graphicsConfiguration, boolean offScreen) {
        super(graphicsConfiguration, offScreen);
    }

    public BufferedImage doRender(int width, int height) {      
        BufferedImage bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGBA, bImage);
        setOffScreenBuffer(buffer);
        renderOffScreenBuffer();
        waitForOffScreenRendering();
        bImage = getOffScreenBuffer().getImage(); 
        setOffScreenBuffer(null);
        return bImage;
    }

    public void postSwap() {}
}

我将它添加为宇宙视图。这里描述了一个主要策略:http://www.java2s.com/Code/Java/3D/PrintCanvas3D.htm

问题在于内存泄漏。我的应用程序开始崩溃,当我尝试配置文件时,我发现OffScreenCanvas3D的实例几乎占据 50MB ,其中大部分来自两个ArrayList秒。较小的一个包含javax.media.j3d.RenderMolecule的实例,较大的一个包含Object的实例,每个实例包含javax.media.j3d.RenderAtomListInfojavax.media.j3d.RenderMolecule

有人可以建议我,我做错了吗?

更新

我想澄清一点,即使根本没有调用doRender(例如,应用程序已启动且不再执行任何操作),内存仍在累积。下面我将添加可以更好地显示情况的图像。

第一个是空闲运行应用程序的内存图。 memory grap

第二个是对象占用的内存饼图。这里(a)是为OffScreenCanvas3D实例分配的内存,(b)是所有其他对象所占用的内存。 memory pie chart

同样在下方,您可以看到dirtyDlistPerRinfoListdirtyRenderMoleculeList占用了大部分空间。任何带有 dirty 前缀的东西都让我感觉代码不好,我不知道为什么 enter image description here

UPDATE2

问题似乎在下一部分:

  1. dirtyDlistPerRinfoList类的updateCanvasResource方法中添加了RenderBin的对象。所有画布都会发生这种情况。
  2. dirtyDlistPerRinfoList已在updateDirtyDisplayLists类的RenderBin方法中清除。
  3. 对于每个正在渲染的Canvas3D,
  4. updateDirtyDisplayListsdoWork(一个可怕的1300行方法)中被调用Renderer
  5. 有一点是offScreen画布不是一直在渲染,而是在图像保存的那一刻。是的,保存图像后,dirtyDlistPerRinfoList中累积的所有内存都被释放。

    接下来的主要问题是:

      

    dirtyDlistPerRinfoList的数据会不断添加到未呈现的画布中,因此不会删除内存。这是我的Java3D错误吗?

4 个答案:

答案 0 :(得分:2)

无。 Java 3D应用程序需要至少25 MB以上的内存以及在RenderMolecule和RenderAtomListInfo类中存储模型所需的内存。请注意,BufferedImages也会消耗大量内存,具体取决于它们的大小。不时调用System.gc()可能会有所帮助。 BufferedImages并不容易删除。

答案 1 :(得分:1)

OffScreenCanvas3D被调用后,doRender只是Renderer.doWork方法的主题。您可以通过覆盖preRender()来证明这一点。添加:

@Override
public void preRender() {
    System.out.println("OffScreenCanvas3D preRender !!!!!!!!!!!!!!!");
}

之后将清除实例的脏列表(如上所述),并在下一次快照时重新使用。

有时名字可能会产生误导。带有前缀“dirty”的列表包含强制下一个渲染循环必要更新的对象。

Java 3D肯定会创建大量冗余数据,以便从渲染数据中分割场景图数据。您的好处是,您可以随时在任何用户线程上调用(几乎)任何Java 3D API方法。无需在Runnable中封装Java 3D代码,因为它是Swing和JavaFX交互或其他构造所必需的。

答案 2 :(得分:1)

JDK工具JConsole允许监视应用程序的内存使用情况。您可以执行垃圾收集器(GC)并检查是否释放了内存。

在程序中调用'java.lang.System.gc()'会产生同样的效果。

Java 3D应用程序本身没有内存泄漏。在撰写这篇文章时,4-Canvas3D示例程序PropellerUniverse正在运行并由JConsole监控。每隔几秒钟,JRE就会自动开始垃圾回收。堆内存使用量为25 MB,非堆内存使用量为34 MB。该程序现在运行25分钟。 http://www.interactivemesh.org/testspace/j3dmeetsswing.html#heavyweight

答案 3 :(得分:0)

尝试消除每一步,直到您找到仍然存在问题的示例。仅执行以下操作时问题是否仍然存在?

// Moved this to be a field
BufferedImage bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGBA, bImage);

OffScreenCanvas3D(GraphicsConfiguration graphicsConfiguration, boolean offScreen) {
    super(graphicsConfiguration, offScreen);
    // set this just once
    setOffScreenBuffer(buffer);
}

public BufferedImage doRender(int width, int height) {
    renderOffScreenBuffer();
    waitForOffScreenRendering();

    // not necessary, image does not change
    // bImage = getOffScreenBuffer().getImage(); 
    // why is this necessary?
    // setOffScreenBuffer(null);

    return bImage;
}
相关问题