【问题标题】:Android Game Garbage Collection Lag alternatives?Android游戏垃圾收集滞后替代品?
【发布时间】:2014-03-03 00:47:27
【问题描述】:

我正在为安卓创建游戏。而且我注意到,每当垃圾收集器启动时,游戏都会出现大量延迟。

App 首次运行时,会创建所有对象并将其添加到 arrayLists 中,如下所示:

br1 = ImgLoader.getResizedBitmap(BitmapFactory.decodeResource(
            context.getResources(), R.drawable.branchfl, MainActivity.opt),
            MainActivity.height / 12, MainActivity.width / 6);

for (int i = 0; i < 10; ++i) {
        branches_available.add(new Sprite("Branch", br1, 0, 0));
    }

Sprite 对象由一个位图和几个允许我修改该位图的方法组成。 所以在上面的代码中,我将 10 个 Sprite 存储到一个 ArrayList 中。现在在代码的后面,我需要动态地将所述精灵生成到我的关卡中。所以我所做的就是:

if (rand == 1) {
            branches_available.get(0).image = bToAdd;
            branches_available.get(0).xPos = (screenWidth - treeWid - bToAdd
                    .getWidth()) + bToAdd.getWidth() / 18;
            branches_available.get(0).yPos = 0 - bToAdd.getHeight();
            branches_available.get(0).height = bToAdd.getHeight();
            branches_available.get(0).width = bToAdd.getWidth();
            branches.add(branches_available.get(0));
            branches_available.remove(0);

这会从第一个数组中取出对象并将其添加到第二个数组中。而在draw方法中,只绘制了第二个arrayList。现在,当对象离开屏幕时,我会执行以下操作:

branchesSize = branches.size();
    for (int i = 0; i < branchesSize; ++i) {
        branches.get(i).move(0, speed);

        if (branches.get(i).yPos > screenHeight) {
            branches_available.add(branches.get(i));
            branches.remove(i);
            i--;
            branchesSize -= 1;
            // System.gc(); // Force Garbage Collection
        }
    }

因此它们被添加回可用数组中,以便在需要时可以在上述方法中再次重用它们。

尽管这样做,我的应用程序仍然存在大量延迟。可能是因为我从数组中删除了对象?

我做错了什么?

谢谢!

【问题讨论】:

  • 我相信这就是为什么某些游戏开发者在本地编写(如果在 Android 上,通过 JNI),因此他们可以手动控制垃圾收集。有些设计可以帮助解决这个问题,但不能完全减轻影响。
  • 感谢您的链接。但是我已经广泛研究了这两个来源并将它们应用到我的代码中。无济于事
  • 在我的游戏中,(我有 2 个在市场上,一个使用画布,一个使用 OpenGL)我有一个声音管理器,对于画布构建的游戏,我有一个位图/精灵管理器。这会调用 Bitmap.recycle & system..gc 来通知 java 尽快收集垃圾。在位图上我希望完成一段时间,并将我最​​需要的位图保存在内存中。如果位图已被回收,接下来我需要它,我重新加载它。其他要做的事情是优化您的精灵表以尽可能小(内存方面)。同样在上面我的意思是说,在 Java 中与 c++ 完全相同的事情是不可能的。
  • 镜像user2046264的评论:你确定这是GC吗?清单有多大?从ArrayList 中删除元素是O(n),并且由于您在n 上循环执行此操作,因此您将获得O(n^2)(慢)性能和ArrayList。您可以考虑使用带有iterator.remove() 功能的LinkedList 来获取O(1) 删除操作:stackoverflow.com/questions/322715/…

标签: java android arrays arraylist bitmap


【解决方案1】:

尝试使用HashMap&lt;String,Bitmap&gt; 并对其进行初始化,以便为您需要的每个图像都有一个键,并将该键设为图像名称。然后创建一个函数,您可以在其中使用键请求图像,该函数将在地图中查找它。如果键处的位图为空,则加载位图并将其设置为键。需要时,您可以使用迭代器迭代哈希图。每次加载位图时,通过将新位图的大小添加到成员字段来跟踪地图中所有位图的大小。当所有位图的总大小开始接近您设置的阈值时,找出一种选择此时不再需要的位图的方法,并调用bitmap.recycle,将该键处的值设置为null,减去大小从所有位图的总大小中删除位图,并通知垃圾收集器。

这将解决数组列表的一些性能问题,并有助于尽快清理内存。棘手的事情是决定要释放哪些位图,如果需要,在需要之前预测或知道:哪些位图要进入内存。

绘制精灵时,最简单的方法是知道偏移量和当前精灵。例如,如果您有一个 500x200 的精灵,第一行有 5 帧,第二行有 5 帧(所以 5 列 2 行),并且您知道精灵的进程从左到右,所以从 ( 0,0) 到 (5,0) 然后再向下 1 和从左到右 (1,0) 到 (1,5) 然后回到 (0,0) 开始,然后您可以创建一个简单的函数会给你你需要的。

在 OpenGL 和 Canvas 中,我都能够使用偏移量来计算要根据当前帧绘制整个位图的哪个部分,因此我在内存中永远不会有超过 1 个位图副本,即使屏幕上有 100 个对象在使用它。

最后,正如我之前在 cmets 中所说,您将希望尽可能减小所有精灵表的大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2019-09-14
    • 1970-01-01
    • 2013-08-09
    • 2019-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多