【问题标题】:Memory leak with an array数组的内存泄漏
【发布时间】:2012-10-16 19:26:40
【问题描述】:

我的 Android 应用程序有一个非常奇怪的内存问题。 我的应用使用以下 3 个类:

public class RGB 
{
    public int R;
    public int G;
    public int B;
}

public class CMYK 
{
    public int C;
    public int M;
    public int Y;
    public int K;
}

public class COLOR 
{
    public String id;
    public CMYK cmyk = new CMYK();
    public RGB rgb = new RGB();

    public COLOR(String id, int c, int m, int y, int k, int r, int g, int b)
    {
        this.id = id;

        this.cmyk.C = c;
        this.cmyk.M = m;
        this.cmyk.Y = y;
        this.cmyk.K = k;

        this.rgb.R = r;
        this.rgb.G = g;
        this.rgb.B = b;
    }
}

然后在代码中,我必须从一个文件中加载 2000 种颜色(文件大约 65K 长,正好有 2000 条记录)并放在 assets 文件夹中

public COLOR[] color_list = new COLOR[2000];
...
...
do
{
    s = reader.readLine();
    if (s != null)
    {
        String[] x = s.split(" ");
        COLOR c = new COLOR(x[0], Integer.parseInt(x[1]), Integer.parseInt(x[2]), Integer.parseInt(x[3]), Integer.parseInt(x[4]), Integer.parseInt(x[5]), Integer.parseInt(x[6]), Integer.parseInt(x[7]));
        color_list[j++] = c;
    }

} while (s != null);

在此之后,应用程序将崩溃并停止工作。如果我删除 do..while 一切正常,所以我认为我的阵列会越来越多,然后 65K,我做错了什么?在 Android LogCat 上,我的 HEAP 空间已满(26MB)!!!

最好的问候 GMG

【问题讨论】:

  • @JarrodSmith:他不是。数组的声明分配了一个数组,而不是 2000 个实际元素。
  • 您可以使用分配跟踪器来确定谁在内存方面使用什么
  • 如果您遇到崩溃,请提供堆栈跟踪。
  • 问题是您没有为数组分配内存,您需要为 x[] 数组中的每个元素分配一个“新”。或者声明你的数组以便分配一些堆。这是错误的:String[] x = s.split(" ");
  • @TanjaV 这是错误的。 split 方法为您分配数组。那行代码没有错。

标签: java android arrays heap-memory android-memory


【解决方案1】:

尝试使用ArrayList 代替基本数组,它使内存管理更容易。

【讨论】:

  • 如果他不需要List 功能,我不明白使用List 的意义。如果其代码存在错误,则该错误取决于其错误,而不是用于存储的数据结构。为什么说ArrayList 会降低内存泄漏的可能性?
  • 空间不用自己分配,可以随意调整大小。避免过度运行索引也更容易,有各种各样的好处。您甚至可以从中获取一个基本数组,用于需要一个方法的方法,例如 SQLiteDatabase 方法。几乎没有理由不使用列表。
  • A List 可以隐藏格式错误的文件。如果他正在分配 恰好 2000 个元素的数组,并用一个应该 恰好 2000 行长的文件填充它,使用 List 可能会隐藏格式错误的文件1999 行,他的应用程序最近会崩溃(或在某些时候行为不端)。
  • 您不需要数组来验证是否正好有 2000 个元素。您阅读所有内容,检查大小,然后做一些明智的事情,而不是仅仅因为 RuntimeException 而炸毁,或者不得不尝试/捕获 RuntimeException。请参阅 Effective Java Item #25 - Prefer lists to arrays for a number of good arguments。
  • 实际上,List 可以很容易地检测和优雅地处理格式错误的文件,而不仅仅是爆炸。
【解决方案2】:

我不认为代码对OutOfMemoryException 负责。可能还有其他领域你没有提到,但是不运行代码就说不出来了。

但是,当您创建 ID 时可能会有泄漏。每当您从现有的 String(基于 substring() 或正则表达式包中的方法)创建 String 时,返回的字符串 keeps an internal reference 到旧的:它只是一个薄包装旧的字符序列,只是不同的开头和不同的长度。这意味着您最好像这样创建您的 ID

String id = new String(x[0]);

这样您就不会为了存储几个字符而将整行保存在内存中。

但是,这是一种优化,因为您声明您的文件为 65KB,因此即使您将其全部保留在内存中,它也不会导致您的应用程序崩溃。发布整个代码,以便我们运行和分析它。

顺便说一句,您可以这样保存缩进级别:

String line;
Pattern pattern = Pattern.compile(" "); // Help the GC ;)

while ((line = in.readLine()) != null) {
    String[] data = pattern.split(line);

    // Ugly, but still better than a 8-args constructor
    RGB rgb = new RGB(data, 1, 3);
    CMYK cmyk = new CMYK(data, 4, 4);

    // the best would be a constructor like Color(String[8])
    colors[j++] = new Color(new String(data[0]), rgb, cmyk);
}

我还稍微更改了 API(我觉得这样更舒服)

【讨论】:

    【解决方案3】:

    很难说没有错误,但我假设你得到一个 IndexOutofBoundExceptions 或其他东西。您将数组初始化为 2000 个元素,但继续阅读您的文件,直到到达末尾。如果里面有 2001 个条目怎么办?然后你会吹过终点。或者如果只有 100 个呢?那你就浪费了很多空间。

    就像 Ralgha 所说,使用 ArrayList,而不是数组。

    对于您的文件解析,您可能需要考虑Scanner 类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-08
      • 2023-03-05
      • 1970-01-01
      相关资源
      最近更新 更多