【问题标题】:Memory leak in Basic GLSurfaceView for androidAndroid 的 Basic GLSurfaceView 中的内存泄漏
【发布时间】: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


【解决方案1】:

内存泄漏和正在运行的 GC 之间总是存在混淆(尽管它们几乎是相反的情况)。当有对阻止 GC 收集这些对象的对象的引用时,就会发生内存泄漏。 GC 收集不再被任何活动线程引用的对象(ListIterator 对象就是这种情况)。

一旦您的线程完成,您的ListIterator 将不再被任何活动线程引用,因此 GC 会收集它。

为防止 GC 运行,请在 Thread 退出之前(在 run() 方法内)自行删除引用 在 run() 方法的末尾取消此对象,或使用您重用的类级别 Iterator 对象每次(不是每次线程运行时都创建一个新对象)。

【讨论】:

  • 这是有道理的。因此,循环的每次迭代我都会创建一个对新迭代器的新引用,而旧的则留给 GC。我的问题是,我将如何将当前迭代器“重置”回 LinkedList 的开头?我知道的唯一方法是调用“.listIterator”方法。附言我希望埃及一切都好。
  • 您可以在 run() 方法的末尾将其设置为 Null,也可以将其定义为 run() 之外的类级别(全局)变量。这使得它被主活动引用,因此只有在主活动被销毁时才会调用 GC。附言非常感谢您的关心:)
猜你喜欢
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多