12

我在 Google 地图上绘制大约 80 个标记时遇到问题。我正在使用 Google Maps Android API v2。

标记的图标是动态的(随时间变化)。向地图添加标记后,无法更改图标。因此,我必须删除所有标记并再次添加所有标记。

mMap.clear();
for (int i = 0; i < teams.length(); i++) {
    team = teams.get(i);
    point = new LatLng(tema.getLatitude(), team.getLongitude());

    MarkerOptions marker = new MarkerOptions().position(point).title(name).icon(BitmapDescriptorFactory.fromResource(team.getMarkerId())));
        mMap.addMarker(marker);
}

多次执行此代码(每分钟刷新一次)后,我得到了 OutOfMemoryExpcetion。

当使用较大的标记图标时,OutOfMemoryException 抛出得更快,所以我认为内存问题与未正确回收的图标位图有关。

我还发现,当将设备的旋转从横向更改为纵向并返回时,会增加使用的堆内存。GC 后内存不会被释放。

有人知道我是否错误地添加了标记,还是我在 Map API 实现中遇到了问题?


我尝试使用 Google Map 示例应用程序重现该错误。在android-sdk/extras/google/google_play_services/samples/maps/src/com/example/mapdemo/MarkerDemoActivity.java标记演示中可以找到。加快测试我增加了创建的标记数量。

int numMarkersInRainbow = 12;

改成

int numMarkersInRainbow = 100;

现在启动演示应用程序,选择标记演示并将设备的旋转从纵向切换到横向并返回几次。

初始堆:

Heap size   Allocated  Free      %Used    #Objects
11,543 BM   9,898 MB   1,645 MB  85,75%   65.982

一些方向更改后的堆:

Heap size   Allocated  Free      %Used    #Objects
15,652 MB   11,337 MB  4,316 MB  72,43%   76.984

经过几次方向更改后的堆:

Heap size   Allocated  Free      %Used    #Objects
21,312 MB   16,411 MB  4,901 MB  77,00%   111.350

最终结果将是 OutOfMemoryExcpetion。

堆转储显示一些可能的堆泄漏:https ://www.box.com/s/rsy0k22dcp267se2g1fy

完整的堆转储:https ://www.box.com/s/6lyv2p6rlc0njqxw5zgu

更新:这似乎与 Android Maps V2 中的内存泄漏问题有关。请参阅https://code.google.com/p/gmaps-api-issues/issues/detail?id=4766 根据问题应该修复但我自己没有测试过。

4

3 回答 3

1

是的,您正面临一个困扰许多 Android 开发人员的非常经典且常见的问题……来势汹汹的 OOM。当您没有在更新或旋转时完全清理旧的可绘制对象时,就会出现此问题。要解决这个问题,你真的应该在 mMap.clear 之前遍历你的标记并将它们设置为 null,并可能通过调用 System.gc() 请求(你不能强制它)垃圾收集。

于 2013-04-05T23:36:56.040 回答
0

这是您可能会采取的一种方法来解决可能的 API 问题...检测设备旋转并通过将 MarketOptions 对象设置为 null 来删除它...然后用您的标记重新填充它。

于 2013-04-05T21:51:41.300 回答
0

每当我的应用程序出现内存泄漏问题时,我都会经历以下场景

  1. 加载应用程序
  2. 执行疑似泄漏内存的操作(最好多执行一次,这样以后更容易分析)
  3. 完成应用程序(按返回直到返回主屏幕)
  4. 分析内存转储

我用于分析的步骤是

  1. 打开直方图
  2. 搜索我的包名
  3. 检查是否有任何不应该的引用

如果存在泄漏并且您多次重复泄漏操作,您将看到片段、活动、视图等的多个实例。为了识别泄漏罪魁祸首:

  1. 右键单击泄漏的对象-> 列出对象-> 带有传入引用
  2. 选择传入的引用之一,右键单击-> GC 根路径-> 排除 WeakReferences
  3. 打开堆栈级别,直到您确定一个引用。如果唯一的路径通向终结器,那么你挖得太深了。如果不确定,请尝试另一个泄漏的对象,重复步骤。

抱歉,这不是一门精确的科学,但它会导致提示,使您能够更轻松地识别泄漏代码。

于 2013-12-26T11:58:18.070 回答