你好再次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变量没有被正确删除。
再次感谢您!