【发布时间】:2012-11-11 21:57:29
【问题描述】:
我从一些 OpenGL/Android 教程中整理了一些我称之为“ViewManager”的东西。问题是我有内存泄漏。我每隔一段时间就会收到 GC 通知,但我不认为我在做任何事情。
11-23 01:50:34.435: D/dalvikvm(954): GC_CONCURRENT freed 381K, 6% free 8024K/8519K, paused 18ms+6ms, total 64ms
我的代码从扩展 GLSurfaceView 并实现 CallBack 和 Runnable 开始。然后,我创建并启动了一个 gameLoop,它处理对象的更新。
正如您从我的代码中看到的,我的列表中还没有任何对象,因此在对象的.draw 或.update 方法中没有发生泄漏。
我在取出游戏循环的情况下运行代码,内存泄漏似乎停止了。有没有人暗示我为什么会收到内存泄漏?附带说明一下,当我删除 run 方法上的 Thread.sleep(30) 调用时,我收到 GC_CONCURRENT 通知的速度要快很多倍!
import java.util.LinkedList;
import java.util.ListIterator;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.MotionEvent;
public class ViewManager extends GLSurfaceView implements Runnable, GLSurfaceView.Renderer
{
private Camera camera;
private ListIterator<GameObject> objIterator;
private LinkedList<GameObject> objects;
private Thread gameThread;
private boolean running;
public ViewManager(Context context)
{
super(context);
setRenderer(this);
objects = new LinkedList<GameObject>();
camera = new Camera();
camera.setPosZ(-4.0f);
}
public void onDrawFrame(GL10 gl)
{
gl.glClear(GL10.GL_DEPTH_BUFFER_BIT|GL10.GL_COLOR_BUFFER_BIT);
//3D Drawing
objIterator = objects.listIterator();
gl.glLoadIdentity();
camera.draw(gl);
while(objIterator.hasNext())
{
gl.glPushMatrix();
objIterator.next().draw(gl);
gl.glPopMatrix();
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
camera.getPreviouslyTouchedPoint().set((int)event.getX(),(int)event.getY());
}
if(event.getAction() == MotionEvent.ACTION_MOVE)
{
camera.setPosX(camera.getPosX() - (camera.getPreviouslyTouchedPoint().x-event.getX())/100f);
camera.setPosY(camera.getPosY() - (camera.getPreviouslyTouchedPoint().y-event.getY())/100f);
}
camera.getPreviouslyTouchedPoint().set((int)event.getX(),(int)event.getY());
return true;
}
public void onSurfaceChanged(GL10 gl, int width, int height)
{
running = false;
gl.glViewport(0,0,width,height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, (float)width/(float)height,0.1f,100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
running = true;
gameThread = new Thread(this);
gameThread.start();
}
public void onSurfaceCreated(GL10 gl, EGLConfig arg1)
{
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearDepthf(1.0f);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
public void run()
{
ListIterator<GameObject> itr = objects.listIterator();
while(running)
{
itr = objects.listIterator();
while(itr.hasNext())
{
itr.next().update(0);
}
try
{
Thread.sleep(30);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
【问题讨论】:
-
似乎只是创建迭代器导致了问题。我注释掉了迭代器的东西,但离开了循环,这就是发生内存泄漏的地方。
-
我自己写了简单的链表和节点迭代方法,现在运行它没有内存泄漏,这让我真的觉得 listIterator() 方法有内存泄漏! (或者我用错了)非常非常非常有趣……
-
你怎么知道你有内存泄漏? GC运行并不意味着你有泄漏(实际上是相反的)
-
hmmm,好问题,我想这可能不是泄漏,但我不明白为什么调用 LinkedList.listIterator() 会导致调用 GC。当我遍历我的自定义链表时,GC 永远不会被调用。
标签: android multithreading opengl-es memory-leaks glsurfaceview