Friday, April 27, 2012

Do not create objects!!!

I posted this as an answer to a post about optimization at stackoverflow. This version is a bit more extended.


Something to think about: DO NOT overuse String, for example in a huge loop. This will create a lot of String objects that have to be GC'ed. The "Bad coding" example will produce 2 string objects every loop. Next example will produce only one final String and a single stringbuilder. This makes a huge difference when optimizing huge loops for speed. I used stringbuilder a lot when making my Wordlist Pro Android app, and it got really speedy when going through 270000 words in no time.
    //Bad coding:
    String s = "";
    for(int i=0;i<999999;i++){
        s = "Number=";
        s = s + i;
        System.out.println(s);
    }

    //Better coding
    final String txt = "Number=";
    StringBuilder sb = new StringBuilder();
    for(int i=0;i < 999999;i++){
        sb.setLength(0);
        sb.append(txt);
        sb.append(i);
        System.out.println(sb);
    }

As an example I wrote this short program to test the real difference in speed. My results are as follows (with my HTC Desire):


Normal String execution time(min-max): 1553ms-1703ms
StringBuilder execution time(min-max): 233ms-402ms


My tests shows that the StringBuilder is roughly about 4-6 times faster than the String in this test.


Most important thing here, is that when running the String version, the GC is invoked at least twice everytime I press the button. StringBuilder does not invoke the garbage collection at all.


Test it your self and keep an eye on the log when you press the buttons. Just copy and paste the code below.
/r0b

HelloWorldActivity.java


public class HelloWorldActivity extends Activity {
    private final static String TAG = "HELLO_DOUBLE";
    private static long startTime = 0;
    private static long estimatedTime = 0;
    private static final int LOOPS = 100000;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button bst = (Button) findViewById(R.id.button_string);
        bst.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView tv1 = (TextView) findViewById(R.id.text1);
                tv1.setText("NormalString:  "+ST()+"ms");
            }
        });
        Button bstb = (Button) findViewById(R.id.button_stringbuilder);
        bstb.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                TextView tv2 = (TextView) findViewById(R.id.text2);
                tv2.setText("StringBuilder: "+SB()+"ms");
            }
        });
    }


    // String = Bad coding:
    private static long ST(){
        startTime = System.currentTimeMillis();    
        String s = "";
        for(int i=0;i < LOOPS;i++){
            s = "Number=";
            s = s + i;
            //Do something
        }
        estimatedTime = System.currentTimeMillis() - startTime;
        return estimatedTime;
    }


    // StringBuilder = Better coding
    private static long SB(){
        startTime = System.currentTimeMillis();    
        final String txt = "Number=";
        StringBuilder sb = new StringBuilder();
        for(int i=0;i < LOOPS;i++){
            sb.setLength(0);
            sb.append(txt);
            sb.append(i);
            //Do something
        }
        estimatedTime = System.currentTimeMillis() - startTime;
        return estimatedTime;
    }


}


main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >


<Button
android:id="@+id/button_string"
android:text="STRING"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</Button>


<TextView
android:id="@+id/text1"
android:text="0"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>


<Button
android:id="@+id/button_stringbuilder"
android:text="STRINGBUILDER"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</Button>


<TextView
android:id="@+id/text2"
android:text="0"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</TextView>


</LinearLayout>

No comments:

Post a Comment