1

Im trying to time the Arraylist and Linkedlist by populating more than million rows and get the below error after the Arraylist population,

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.lang.Integer.valueOf(Integer.java:642) at scratch.Collectionss.main(Collectionss.java:25)

How do I avoid this error, I tried setting the l1 = null but that gives me a error,

public class Collectionss {
    public static void main(String[] args){
        // 
        long starttime = System.currentTimeMillis();
        List<Integer> l1 = new ArrayList<Integer>();
        for (int i = 1; i <= 10000000; i++){
            l1.add(i);
        }
        System.out.println(l1.size());

        long endtime = System.currentTimeMillis();

        System.out.println(endtime - starttime);

        //
        long starttime1 = System.currentTimeMillis();
        List<Integer> l2 = new LinkedList<Integer>();
        for (int i = 1; i <= 10000000; i++){
            l2.add(i);
        }
        System.out.println(l2.size());

        long endtime1 = System.currentTimeMillis();

        System.out.println(endtime1 - starttime1);

    }

}
Peter Lawrey
  • 498,481
  • 72
  • 700
  • 1,075
user1050619
  • 16,744
  • 58
  • 193
  • 347
  • 1
    Initialize the capacities of the ArrayList and LinkedList. That would help. `List l1 = new ArrayList(10000000);`. This will also make your timing more accurate because you won't be resizing the list every iteration of the loop. Other than that, you might truly be running out of memory. – crush Sep 10 '13 at 15:31
  • possible duplicate of [How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size)](http://stackoverflow.com/questions/37335/how-to-deal-with-java-lang-outofmemoryerror-java-heap-space-error-64mb-heap) – Julien Sep 10 '13 at 15:31
  • Also, you should print out the size of the list, after taking the end time - to make sure your timings are most accurate. – crush Sep 10 '13 at 15:34
  • `tried setting the l1 = null but that gives me a error` What error? Unless you put that line before your `System.out.println(l1.size());` line I'm not sure why you would be seeing that. – Paul Richter Sep 10 '13 at 15:35
  • @Teeg If l1 is null,`l1.add` results in a NPE. – Fritz Sep 10 '13 at 15:37
  • @crush Shouldn't the internal copies be garbage collected? The list also grows it's capacity with the formula `(oldCapacity * 3)/2 + 1`, so not every iteration causes a copy. Tho I agree with the principle. – mabi Sep 10 '13 at 15:37
  • 1
    @Teeg--You are correct, null works , I think I have done something wrong earlier..Thanks – user1050619 Sep 10 '13 at 15:38
  • @mabi Not every iteration causes a copy, but the final copy is almost certainly guaranteed to be much larger than it needs to be to fit the data. Thus, he's not making the most efficient use of his memory. Also, if his attempt at profiling is to time the `add()` operation of each, then he won't want to resize on those operations. – crush Sep 10 '13 at 15:39
  • @Gamb Yeah, but that's what I mean, it depends on where the OP placed the nullification line; if they did it within the loop, or before the println(li.size()), then yes of course, but outside of that, I don't see why they would get such an error, since they don't use `li` after that point. – Paul Richter Sep 10 '13 at 15:39
  • @user1050619 Ok cool. Glad I could help. – Paul Richter Sep 10 '13 at 15:40
  • @crush Totally agree on the inefficient bit, just took issue with the "resizing every iteration" thing (because that's what *I* thought the JVM is doing before someone told me). – mabi Sep 10 '13 at 16:25
  • @mabi Sorry. That was my failure at trying not to explain the exact resize algorithm within the space of my comment. I should have been more explicit. Thanks for the correction. – crush Sep 10 '13 at 16:27

6 Answers6

6

You should be running these tests in separate methods as the optimisation of the first loop can interfere with the optimisation of the second i.e. the second one can be slower, just because it is second.

I suggest you run both tests at least 10 (or for 2 seconds) and use System.nanoTime() which has higher resolution.

If you do this and you still run out of memory I suggest you increase the maximum memory size. If you are running 32-bit windows, the default is very low. You can increase it with -Xmx1g on the command line


If you run the following, you can see that GCs have the biggest impact which is not surprising as the problem most produces garbage

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class Collectionss {

    public static final int TO_ADD = 10000000;

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            long timeAL = timeAddToArrayList();
            long timeLL = timeAddsToLinkedList();
            System.out.printf("Time to add %,d Integer to ArrayList %.3f sec, LinkedList %.3f%n",
                    TO_ADD, timeAL / 1e9, timeLL / 1e9);
        }
    }

    private static long timeAddToArrayList() {
        long starttime = System.nanoTime();
        List<Integer> l1 = new ArrayList<Integer>();
        for (int i = 1; i <= TO_ADD; i++) {
            l1.add(i);
        }
        assert TO_ADD == l1.size();

        return System.nanoTime() - starttime;
    }

    private static long timeAddsToLinkedList() {
        long starttime = System.nanoTime();
        List<Integer> l2 = new LinkedList<Integer>();
        for (int i = 1; i <= TO_ADD; i++) {
            l2.add(i);
        }
        assert TO_ADD == l2.size();

        return System.nanoTime() - starttime;
    }
}

prints

Time to add 10,000,000 Integer to ArrayList 0.238 sec, LinkedList 1.326
Time to add 10,000,000 Integer to ArrayList 1.193 sec, LinkedList 0.971
Time to add 10,000,000 Integer to ArrayList 0.841 sec, LinkedList 0.048
Time to add 10,000,000 Integer to ArrayList 0.349 sec, LinkedList 1.128
Time to add 10,000,000 Integer to ArrayList 0.064 sec, LinkedList 0.048

However add System.gc() before each test and you get

Time to add 10,000,000 Integer to ArrayList 0.241 sec, LinkedList 2.130
Time to add 10,000,000 Integer to ArrayList 0.070 sec, LinkedList 0.072
Time to add 10,000,000 Integer to ArrayList 0.067 sec, LinkedList 0.053
Time to add 10,000,000 Integer to ArrayList 0.069 sec, LinkedList 0.048
Time to add 10,000,000 Integer to ArrayList 0.065 sec, LinkedList 0.051
Peter Lawrey
  • 498,481
  • 72
  • 700
  • 1,075
  • 1
    I tend to follow another post of yours on the subject, where you suggest 10 times at least. It works rather well for me. – crush Sep 10 '13 at 15:40
  • 1
    Yes, one should always use `System.nanoTime()` over `System.currentTimeMillis()`. – mike Sep 10 '13 at 15:40
2

try increasing your heap size and run your program

2

If you are dealing with large data sets, then its always better to initialise your ArrayList with the correct size, in your case.

List<Integer> l1 = new ArrayList<Integer>(10000000);, otherwise your ArrayList will be having a default size of 10, and every time once the size is exceeded, the add method will create a new array of increased size copying all the contents of the old array inside your arraylist.

See the source below from ArrayList ensureCapacity method.

if (minCapacity > oldCapacity) {
    Object oldData[] = elementData;
    int newCapacity = (oldCapacity * 3)/2 + 1;
        if (newCapacity < minCapacity)
    newCapacity = minCapacity;
        // minCapacity is usually close to size, so this is a win:
        **elementData = Arrays.copyOf(elementData, newCapacity);**
}

And if its still happens, even after initialising then increase your heap size as others suggested in the post.

Sajan Chandran
  • 10,561
  • 3
  • 25
  • 37
1

You need to increase the heap availbable to the JVM via the-Xmx4g flag. This will increase the heap size to 4GB. You don't need a command line for that. IDE also accept JVM parameters. E. g. eclipse: Run Configurations... -> Arguments -> VM Arguments

As @crush mentioned you could save memory (resp. the GC some work), if you initialize the ArrayList with the needed capacity.

mike
  • 4,509
  • 4
  • 33
  • 72
1

I think you can specify the heap size whenever you run your program. If you are executing on the command line, whenever you execute using "java " include a parameter: "-Xms1024m -Xmx1024m" or whatever you want your heap size to be. Look jvm launch parameters to get the exact usage.

zero298
  • 20,481
  • 7
  • 52
  • 83
0

You are adding 10000000 items in your List collection. Each time will surely add to the memory consumption and finally crossing the heap size.

And you are creating such a collection twice.

You need to figure out why do you need such a big collection. If you need such big collections then you need to have desired increase heap space.

Juned Ahsan
  • 63,914
  • 9
  • 87
  • 123
  • 2
    Not to mention, his collections are going to dynamically expand as the collection size grows. He should specify the initial capacity ahead of time, since he knows it. This will save both memory, and make his timings more accurate. – crush Sep 10 '13 at 15:32
  • This works...List l1 = new ArrayList(10000000); but List l2 = new LinkedList(10000000); fails..Looks like LinkedList does not take a pre-defined size... – user1050619 Sep 10 '13 at 15:40
  • @user1050619 That's because linked lists aren't arrays. Sorry for misrepresenting this fact. – crush Sep 10 '13 at 15:41
  • An array list isn't an array neither, it's just backed by one :P – mike Sep 10 '13 at 15:42
  • `ArrayList` has an internal array that must be resized when the number of elements it contains exceeds the size of the array. That's why it is better to explicitly set the capacity if you know it before hand. – crush Sep 10 '13 at 15:43