【问题标题】:Improving for-each performance提高 for-each 性能
【发布时间】:2015-05-06 22:37:32
【问题描述】:

我的 Android 应用程序中不断运行以下 CountDownTimer

CountDownTimer timer_status;
timer_status = new CountDownTimer(1000,1000) {

    List<Integer> lst = new ArrayList<Integer>();
    int k=0;
    @Override
    public void onTick(long millisUntilFinished) {


        String S = "";
        k=0;
        byte[] writeBuffer = new byte[8];

        for (int value : lst) {

            if(k==8) {
                k=0;
                S="";
             }

            S = S + String.format("%02x ", value).toUpperCase();
            writeBuffer[k] = (byte) value;
            k++;

        }

        editSent.setText(S);                            
}

每个循环,应用程序都会从​​整数的List 创建一个新的byte[] 缓冲区。

它工作正常,但在 LogCat 上生成 GC_FOR_ALLOC

03-05 11:12:41.330: D/dalvikvm(21178): GC_FOR_ALLOC freed 511K, 19% free 4662K/5720K, paused 14ms, total 14ms
03-05 11:12:42.250: D/dalvikvm(21178): GC_FOR_ALLOC freed 511K, 19% free 4662K/5720K, paused 15ms, total 15ms

GC_FOR_ALLOC 被触发,因为堆上没有足够的内存来执行分配。可能会在创建新对象时触发。

如何改进这个foreach 循环,在堆上留下足够的内存?

【问题讨论】:

  • 当你像这样使用String时,它每次都会创建唯一的String并将它们放入String Pool中。使用 StringBuilder 以获得更好的性能。
  • 谢谢。这是开始改进它的好方法。
  • 对幻数使用静态final?

标签: java android arrays foreach


【解决方案1】:
 StringBuilder sb = new StringBuilder(); 
 k=0; 
 byte[] writeBuffer = new byte[8];

 for (int value : lst) { 
 if(k==8) { k=0; sb.setLength(0); 
 } 
 sb.append(String.format("%02x ", value)); 

 writeBuffer[k] = (byte) value; k++; 
 }

 editSent.setText(sb.toString().toUpperCase());

除了StringBuilder,我想指出的是普通for在Android中比foreach有更好的性能,因为foreach循环创建了一个隐藏的Iterator对象。因此,请避免在 Android 的性能关键代码中使用 for-each。

另外,如果可能的话,对原始类型使用普通的Array 而不是ArrayList,因为自动装箱/拆箱会在每个循环中进行,这会影响您的性能。

【讨论】:

  • 能否请您演示一下 StringBuilder 如何适合我的上下文?
  • StringBuilder sb = new StringBuilder(); k=0;字节[] writeBuffer = 新字节[8]; for (int value : lst) { if(k==8) { k=0; sb.setLength(0); } sb.append(String.format("%02x ", value).toUpperCase()); writeBuffer[k] =(字节)值; k++; } editSent.setText(sb.toString());
【解决方案2】:

使用 StringBuilder 是一回事(见评论)。

您还可以避免使用局部变量 SwriteBuffer 并改用类变量,这样可以在每次调用时有效地重用这两个变量,而不是将它们传递给垃圾回收。

【讨论】:

  • 为什么类变量S会更好?我认为这是完全错误的......(此外,它会导致 S 后面的字符串被引用的时间比需要的时间长!)
  • 如果垃圾回收有问题,关键是防止垃圾。如果你知道你经常需要一个变量,那么将它声明一次,将它保存在类中,并在每次使用后清理它会更有效。 clean 表示干净,不设置为 null(再次将其传递给 GC)。
  • 我相信情况并非如此,因为它们会像你提到的那样经常使用,而不是经常使用。
猜你喜欢
  • 1970-01-01
  • 2010-09-17
  • 2018-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
相关资源
最近更新 更多