Java图像缩放功能有某种内存泄漏

时间:2016-10-23 21:17:26

标签: java memory memory-leaks game-engine bufferedimage

你好再次stackoverflow,所以我正在研究我的最新项目,一个石油大亨游戏,受到电影的启发。它涉及一个可以放大的世界地图,为此我有一个功能,根据您滚动的数量将图像缩放到一定的大小。我已经习惯了C ++,你手动释放内存,所以请放轻松我,因为我不完全理解垃圾收集器,什么不是,英语也不是我的母语。

功能就是这个(部分来自stackoverflow,我爱你们):

public void scale(int dWidth, int dHeight) {

    Image newImg = this.baseImg.getScaledInstance(dWidth, dHeight, Image.SCALE_DEFAULT);
    // Create a buffered image with transparency
    BufferedImage bimage = new BufferedImage(newImg.getWidth(null), newImg.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    // Draw the image on to the buffered image
    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(newImg, 0, 0, null);
    bGr.dispose();
    this.img.flush();
    this.img = bimage;
    bimage.flush();
    newImg.flush();

}

此函数是类Bitmap的一部分,它具有BufferedImage成员变量img。该成员变量用于在屏幕上实际绘制图像。然而,在测试我的新缩放功能时,我注意到在调用函数时内存使用率暴涨。而且,内存实际上并没有被释放。我测试了它,并且没有调用scale函数,内存使用率稳定在大约200MB左右,但是一旦我开始调用这个函数(仅针对一个图像,每次MouseWheelMoved事件触发时调用),一旦你滚动它就会飙升。每个滚动都会大量增加内存使用量,而且它永远不会减少。我已经添加了flush调用,但似乎没有任何效果。也没有将局部变量设置为null。我怀疑这个函数中存在某种内存泄漏。

所以我向你们提问:任何人都可以证实这一点吗?有没有人在这个函数中看到内存泄漏?如果没有,在调用此函数时还有什么可能导致内存使用量的这种荒谬的增加?我只想再次强调,我100%确定这个功能是它的原因。

如果需要,我可以发布更多代码(例如对函数的实际调用),但我暂时省略了它。

提前致谢!

修改

根据要求添加了额外的代码。

让我们从上到下潜入这个兔子洞。

首先,我有一个类GameWindow,它扩展了JFrame。它有一个像这样的MouseWheelListener:

    this.addMouseWheelListener(new MouseWheelListener(){

        @Override
        public void mouseWheelMoved(MouseWheelEvent arg0) {

            double scrollAmount  = arg0.getPreciseWheelRotation();

            curMapScale -= ((double)scrollAmount * 0.1);
            // Reset zooming
            if(curMapScale <= 0)
            {
                curMapScale = 1.0;
            }



        }

    });

我的游戏循环就是这样(我知道,这是非常的):

private void gameLoop()
{

    boolean abort = false;

    long curTime = 0;
    long prevTime = System.currentTimeMillis();

    while(!abort)
    {
        curTime = System.currentTimeMillis();

        // 500ms for debugging the scaling issue
        if(curTime - prevTime > (500))
        {
            prevTime = curTime;
            wGame.render();
        }

    }
}

wGame是GameWindow对象,它的渲染功能是这样的:

public void render()
{
    mainPanel.updateGame();
    mainPanel.render();
}

mainPanel是GraphicsPanel的一个对象,它是一个扩展JPanel的类。 这是updateGame()函数:

public void updateGame()
{
    em.update();
}

它的渲染功能:

public void render()
{
    this.repaint();
}

最后是scaleEntities()函数

public void scaleEntities()
{
    // Deleted scaling of all entities except the map in order to debug the scaling issue
    em.scaleMap(getWidth() * GameWindow.curMapScale, getHeight() * GameWindow.curMapScale );    
}

em是EntityManager类的一个对象,该类包含与游戏世界中每个实体一起使用的ArrayLists。它的更新功能如下:

public void update()
{
    // Loop through all generic entities en update them (entityList is empty  
    // for the moment
    for(int i = 0; i < entityList.size(); i++)
    {
        entityList.get(i).update();
    }
    // Loop through all pointsOfInterests, which exist only on the overworld
    // also empty for the moment
    for(int i = 0; i < pointsOfInterest.size(); i++)
    {
        pointsOfInterest.get(i).update();
    }
    // Update the current map (note the update() function isn't actually used yet, it will be used to update an entities position if it has a velocity
    mapList.get(curMap).update();

    // Stuff pertaining to Window Resizing, which is irrelevant right now
    GameWindow.resetOffset();
    GameWindow.hasMouseDragged = false;
}

它的scaleMap()函数是这样的:

public void scaleMap(double width, double height)
{
    mapList.get(curMap).scale((int)Math.ceil(width), (int)Math.ceil(height));
}

此函数中的缩放调用直接传递给地图的Bitmap对象。因此我们开始使用的缩放函数。

最后但并非最不重要的是,GraphicsPanel类的paintComponent()函数,其中实际绘制了对象:

public void paintComponent(Graphics g)
{
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.WHITE);
    g2d.fillRect(0, 0, getWidth(), getHeight());
    em.render(g2d);
}

EntityManagers渲染功能:

public void render(Graphics2D g2d)
{
    // Only draw the map for debugging purposes
    mapList.get(curMap).draw(g2d);

//  for(int i = 0; i < entityList.size(); i++)
//  {
//      entityList.get(i).draw(g2d);
//  }
//  for(int i = 0; i < pointsOfInterest.size(); i++)
//  {
//      pointsOfInterest.get(i).draw(g2d);
//  }
}

地图绘制功能:

@Override
public void draw(Graphics2D g2d) {
    BufferedImage temp = bitm.getSource();

    g2d.drawImage(temp, (int)this.loc.getX(), (int)this.loc.getY(), null);

    temp.flush();

}

bitm显然是地图的Bitmap成员,它的getSource()函数是这样的:

public BufferedImage getSource()
{
    return this.img;
}

这应该是所有相关的代码。有人看到内存泄漏可能来自哪里吗?我感觉Bitmaps比例功能中的newImg和bimage变量没有被正确删除。

再次感谢您!

0 个答案:

没有答案