简体   繁体   中英

Why does reassigning a variable to a new String take so much time in Java?

A few days ago I realized that I had never done any experimentation with measuring the time it takes for a program to run. I decided for fun just to test out some random lines of code for the heck of it using the System.currentTimeMillis() method. I decided to try out something simple, such as merely continuously reassigning a variable. So, I ran the following code:

public class Timer{
    public static void main(String[] args) {
        String s = null;

        final long startTime = System.currentTimeMillis(); // Start the timer

        for (int i = 1; i <= 999999999; i++) { 
            s = i + "Hello";  // This takes around 36 seconds!
        }

        System.out.println(s);

        final long endTime = System.currentTimeMillis(); // End the timer

        System.out.println("Total execution time: " + (endTime - startTime)); // Report total time elapsed
    }
}

I was amazed to see that just continuously reassigning a String variable would take so long. I know the number up to which I'm iterating is quite huge in and of itself, but when I ran other code that still involved the for-loop up to that huge number, the time it took for the program to run was significantly lower. For example:

import java.util.ArrayList;

public class TimerArrayList {
    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<Integer>();

        final long startTime = System.currentTimeMillis(); // Start the timer

        // Adding elements to an ArrayList is generally quick (around 4 seconds)
        for (int i = 1; i <= 999999999; i++) {
            list.add(i);
            if (list.size() == 50000)
                list.clear(); // To prevent OutOfMemoryError
        }
        final long endTime = System.currentTimeMillis(); // End the timer
        System.out.println("Total execution time: " + (endTime - startTime)); // Report total time elapsed
    }
}

Adding elements to the ArrayList took only about 4 seconds. Even faster yet was merely counting up. For instance, this code took on average 1.5 milliseconds to run:

public class TimerCounting{
    public static void main(String[] args) {
        final long startTime = System.currentTimeMillis(); // Start the timer

        // Just counting up is super quick (around 1 millisecond)
        int counter = 0;
        for (int i = 1; i <= 999999999; i++) {
            counter = i;
        }

        final long endTime = System.currentTimeMillis(); // End the timer

        System.out.println("Total execution time: " + (endTime - startTime)); // Report total time elapsed
    }
}

So, my question is: why does it take so long just to reassign a String variable?

Reassigning of strings is a costly operation and every time we reassign a string a couple of operations actually happen in the background due to the immutable nature of strings.

This is why concatenating Strings many, many times is a bad idea. Each time you concatenate, your application takes the hit of implicitly making a new String and for this exact purpose we have StringBuffer/StringBuilder

Case 1:

for (int i = 1; i <= 999999999; i++) {
            counter = i;
}

You are not allocating any new memory to variable counter . Hence it just take 1 cpu cycle to run counter = i in each iteration.

Case 2:

for (int i = 1; i <= 999999999; i++) {
    list.add(i);
    if (list.size() == 50000)
       list.clear(); // To prevent OutOfMemoryError
}

It generally takes more than 1 cpu cycles to add an element in list. It first searches for a free space in memory, allocates the space for new element in list and then does some piece of code to actually add the new element in to end of linked list.

Actually, overall Time taken should be more than 4 seconds . but as you are doing this in batch (allowing old memory to be garbage collected after 50000th element), this will less time when finding new space for new element because of less page swappings.

Case 3:


 for (int i = 1; i <= 999999999; i++) { 
   s = i + "Hello";  // This takes around 36 seconds!
 }

This allocates memory from heap as new string is created each time with different value of i.

Probably in your case, It constanly adds to heap space when creating new string literal until the next garbage collector cycle runs. (Unlike the case of linked list where the memory was cleared on encoutering 50000th element.)

Hope this clears to some extent !

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM