嵌套循环导致android中的大量垃圾收集?

Posted

技术标签:

【中文标题】嵌套循环导致android中的大量垃圾收集?【英文标题】:Nested loop causing massive Garbage collection in android? 【发布时间】:2014-02-06 06:46:58 【问题描述】:

我在android中有这段代码,导致大量的GC日志

    // When turning into frequency domain we'll need complex numbers:
    byte audio[] = out.toByteArray();  //approx size 827392
    int amountPossible = 200;
    Complex[][] results = new Complex[amountPossible][];

    // For all the chunks:
    for (int times = 0; times < amountPossible; times++) 
        Complex[] complex = new Complex[4096];
        for (int i = 0; i < 4096; i++) 
            // Put the time domain data into a complex number with imaginary
            // part as 0:
            complex[i] = new Complex(audio[(times * 4096) + i], 0);
        
        // Perform FFT analysis on the chunk:
        results[times] = FFT.fft(complex);
    

以下是一些日志

    D/dalvikvm(10602): GC_CONCURRENT freed 805K, 88% free 3911K/31075K, paused 2ms+5ms
     D/dalvikvm(10602): GC_CONCURRENT freed 1796K, 88% free 3957K/31075K, paused 1ms+2ms
     D/dalvikvm(10602): GC_CONCURRENT freed 1811K, 88% free 3970K/31075K, paused 1ms+3ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1711K, 87% free 4102K/31075K, paused 2ms+3ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1806K, 87% free 4138K/31075K, paused 1ms+3ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1755K, 87% free 4226K/31075K, paused 1ms+3ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1827K, 87% free 4242K/31075K, paused 1ms+3ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1732K, 87% free 4258K/31075K, paused 2ms+2ms
    D/dalvikvm(10602): GC_CONCURRENT freed 1714K, 86% free 4387K/31075K, paused 1ms+3ms

提前致谢

【问题讨论】:

您创建了4096^2 对象——您真的使用了所有这些对象吗?不要忘记您使用的是内存有限的手机! 那么您的实际问题是什么?到目前为止,唯一可能的答案是“是的 - 这是此类代码的预期行为” 当我注释掉“results[times] = FFT.fft(complex);”这一行时GC 日志已停止。复数的 FFT 是不是很繁重的运算? 当我在我的程序中执行循环时,这个确切的 gc 确实有类似的问题,你找到解决方案了吗? 不,我开始认为在 Android 手机中对复数执行 FFT 是一项繁重的操作,并且会占用大量内存。 【参考方案1】:

您的问题是,在 Java 中,Complex 是一个堆分配的 Java 对象。我相信它是不可变的,因此必须为每次计算创建新的Complex 实例。这使得对复数进行数学运算变得极其缓慢并分配了大量内存。因此应尽可能避免。

纯 Java 中唯一的解决方案是不使用内置的 Complex 类型,而是直接对成对的 double 数组进行 FFT,实部和虚部各一个。或者,可以使用包含实部和虚部的单个数组,尽管this question 的 cmets 暗示第一种方法往往会提供更好的性能。缺乏非堆分配对象是 JVM 的一个不幸限制。

要获得更高的性能,最好的方法是使用本机库。一种选择是FFTS,它是 BSD 许可的并带有 JNI 绑定。它使用运行时代码生成和 SIMD 指令来实现远高于任何纯 Java 库的性能。

【讨论】:

以上是关于嵌套循环导致android中的大量垃圾收集?的主要内容,如果未能解决你的问题,请参考以下文章

大量内存溢出导致堆大小在大约 8 秒内从大约 64mb 变为 1.5gb。垃圾收集器的问题?

垃圾收集器与内存分配策略---垃圾收集算法

Javascript / 垃圾收集器中的循环引用

垃圾收集器与内存分配策略之垃圾收集算法

垃圾收集器

垃圾收集算法!