【问题标题】:HashMap into ArrayList Out of MemoryHashMap 到 ArrayList 内存不足
【发布时间】:2016-06-03 11:59:06
【问题描述】:

我有类似的代码:

ArrayList<HashMap<String, String>> myArray = new ArrayList<HashMap<String, String>>();

for(int i=0; i<8000; i++){

  HashMap <String, String> hashMap = new HashMap<String, String>();

  hashMap.put("key1", string1);
  hashMap.put("key2", string2);

  myArray.add(hashMap);
}

有时在旧版 Android 设备中,此代码会导致 new HashMap 上的 OutOfMemory。

有没有办法改进这段代码? 谢谢

编辑:

我的应用程序类中有这个结构来检索应用程序周围的这个数组并执行类似的操作:

ArrayList<String> allObj1 = new ArrayList<String>();
ArrayList<String> allObj2 = new ArrayList<String>();

for (int i = 0; i<myArray.size(); i++) {

    String obj1 = myArray.get(i).get("key1");
    String obj2 = myArray.get(i).get("key2");

    allObj1.add(obj1);
    allObj2.add(obj2);
 }


 String[] stringObj1 = allObj1.toArray(new String[allObj1.size()]);
 String[] stringObj2 = allObj2.toArray(new String[allObj2.size()]);

 list.setAdapter(new Adapter(this, stringObj1, stringObj2));

【问题讨论】:

  • 在 codereview 上试试这个
  • 为什么需要一个包含 8000 个相同哈希图的列表?
  • @zapl "similar code" string1 和 string2 对于每个 i 总是不同的
  • 仅供参考,这不是内存泄漏,这是内存不足。
  • 这并不是真正的“泄漏”内存,是吗?您只是创建了一堆哈希映射,然后将它们存储在一个列表中。假设您持有 myArray,则哈希映射(和列表)不符合 GC 条件。

标签: java android arraylist hashmap


【解决方案1】:

你可以稍微改进一下你的代码,我会写两个解决方案,第一个更好,但是如果你不能使用它,请使用第二个:

在这两种解决方案中,都使用具有初始容量的构造函数。

如果您可以更改 int 值中的键,请使用 SparseArray

ArrayList<SparseArray<String>> myArray = new ArrayList<>(8000);
for(int i=0; i<8000; i++) {
    SparseArray<String> sp = new SparseArray<>(2);
    sp.put(1, string1);
    sp.put(2, string2);
    myArray.add(sp);
}

改用ArrayMap

ArrayList<ArrayMap<String, String>> myArray = new ArrayList<>(8000);
for (int i = 0; i < 8000; i++) {
    ArrayMap<String, String> am = new ArrayMap<>(2);
    am.put("key1", string1);
    am.put("key2", string2);
    myArray.add(am);
}

【讨论】:

  • 谢谢你的回答,为什么ArrayMap比HashMap好?
  • @Ilario 因为HashMap 为每对键/值创建了一个对象 (Entry)。相反,ArrayMap 创建了一个键数组和一个值数组。
  • @Ilario ArrayMap 已添加到 api 19,但也可用于 api 9
  • @Fondesa 但 Android Studio 告诉我“调用需要 Api 级别 19(当前最低为 9)
  • @Ilario 你必须导入android.support.v4.util.ArrayMap 而不是android.util.ArrayMap
【解决方案2】:

我的回答来自here

为什么不创建一个保存你的属性的对象

喜欢这个

class A{
String key1;
String key2;
}
 ArrayList<A> myArray = new ArrayList<A>();
for(int i=0; i<8000; i++) {
    A a=new A();
    a.key1=string1;
    a.key2=string2;
    myArray.Add(a);
 } 

我在这里想说的是,hashmap 对象具有可以使用对象缩小的开销

【讨论】:

    【解决方案3】:

    你的代码应该改成:

    String[] stringObj1 = new String[myArray.size()]);
    String[] stringObj2 = new String[myArray.size()]);
    for (int i = 0; i < myArray.size(); i++) {
      stringObj1[i] = myArray.get(i).get("key1");
      stringObj2[i] = myArray.get(i).get("key2");
    }
    list.setAdapter(new Adapter(this, stringObj1, stringObj2));
    

    这可以防止中间列表并节省内存。如果两个数组的内存不可用,则复制操作不会开始。

    myArray 似乎不是一个数组而是一个列表。 :o

    【讨论】:

    • 感谢您的回答,myarray 就是这个 ArrayList> myArray = new ArrayList>();
    【解决方案4】:

    你所做的已经足够好了。唯一需要担心的是设备每次都没有那么多内存可以分配给新的 hashmap 对象。

    当您启动 JVM 时,您可以定义它可以使用多少 RAM 来进行处理。 JVM 将其划分为特定的内存位置用于处理目的,其中两个是 Stack & Heap

    OutOfMemoryError 与堆有关。如果内存中有大对象(或)引用的对象,那么您将看到 OutofMemoryError。如果您对对象有强引用,则 GC 无法清理为该对象分配的内存空间。当 JVM 尝试为新对象分配内存但没有足够的可用空间时,它会抛出 OutofMemoryError,因为它无法分配所需的内存量。

    如何避免:确保不必要的对象可用于 GC

    StackOverflowError 与堆栈有关。您所有的局部变量和方法调用相关数据都将在堆栈上。对于每个方法调用,将创建一个堆栈帧,并且本地以及与方法调用相关的数据将放置在堆栈帧内。一旦方法执行完成,堆栈帧将被删除。重现此问题的一种方法是,对方法调用进行无限循环,您将看到 stackoverflow 错误,因为每次调用都会使用方法数据填充堆栈帧,但不会释放(删除)。

    如何避免确保方法调用结束(不是无限循环)

    【讨论】:

      【解决方案5】:
      ArrayList<HashMap<String, String>> myArray = new ArrayList<HashMap<String, String>>();
      HashMap <String, String> hashMap = new HashMap<String, String>();
      for(int i=0; i<8000; i++) {     
          hashMap.put("key1", string1);
          hashMap.put("key2", string2); 
          myArray.add(hashMap);
      } 
      

      像这样在 for 循环外声明 hashMap。您在内存池中一次又一次地创建对象。

      【讨论】:

      • 你创建了同一个HashMap实例的列表,结果不是OP所期望的
      • 这与 OP 在他/她的代码中所做的非常不同。
      • 我已经为您提供了内存不足异常的解决方案 .. 不是您想要的输出,对于您的 OP 提出不同的问题或编辑您的问题
      猜你喜欢
      • 2012-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2010-12-04
      相关资源
      最近更新 更多