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
Answer from Peter Lawrey on Stack Overflow
๐ŸŒ
Coderanch
coderanch.com โ€บ t โ€บ 614644 โ€บ java โ€บ Arraylist-heapsize-memory-error
Arraylist vs heapsize: Out of memory error (Performance forum at Coderanch)
And this is where the penalty is - if I've expected a list to contain 10,000 elements when I've coded it, but then reorganized the data into 200 lists of 50 elements each and forgot to change the initial capacity guess, I'm now wasting some 1,900,000 object references (about 8 MB in 32 bit JVM)!. And unlike the first case, this memory is allocated for the lifetime of the entire ArrayList (or until trimToSize() is called), whereas in the first case most of the memory allocated in excess is immediately freed.
Top answer
1 of 6
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
2 of 6
4

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.

Discussions

java - ArrayList Out of Memory Error - Stack Overflow
I am trying to Retrieve 100,000 records from an SQL database but I am having an Out of Memory Error when using ArrayList. How can I optimize my code to achieve this? How can I apply a flyweight d... More on stackoverflow.com
๐ŸŒ stackoverflow.com
arrays - ArrayList and java.lang.OutOfMemoryError - Stack Overflow
I am trying to make program that create an ArrayList of initial size of 1 and populate it with random numbers. Next, the ArrayList is cleared and the size of ArrayList is increased by 1 and again ... More on stackoverflow.com
๐ŸŒ stackoverflow.com
java - Behaviour of JVM during out of memory error? List s = new ArrayList<String>(); - Stack Overflow
The OutOfMemoryError probably occurs when the list(?) represented by s tries to allocate memory to store the string. If s is an ArrayList for instance, this operation can be quite expensive (since the ArrayList uses array doubling). More on stackoverflow.com
๐ŸŒ stackoverflow.com
collections - ArrayList - java.lang.OutOfMemoryError: Java heap space - Stack Overflow
the problem is that there are more than a million entries in my list, after which it falls. I need the whole list to pass it to jasper to generate a report. Can someone tell me how to deal with this? More on stackoverflow.com
๐ŸŒ stackoverflow.com
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 49910835 โ€บ arraylist-java-lang-outofmemoryerror-java-heap-space โ€บ 49911217
ArrayList java.lang.OutOfMemoryError: Java heap space - Stack Overflow
April 19, 2018 - I also agree, so sort of "cached" list would seem like a better long term solution ... @MadProgrammer Even more confused now. This is not about performance. And only secondarily about the memory consumption per se. This is about the fact that in practice, you cannot have a Java Collection with more than 2^31 elements (and still expect it to work properly).
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 42073539 โ€บ arraylist-out-of-memory-error
java - ArrayList Out of Memory Error - Stack Overflow
I am trying to Retrieve 100,000 records from an SQL database but I am having an Out of Memory Error when using ArrayList. How can I optimize my code to achieve this? How can I apply a flyweight design pattern to my code? import java.math.BigDecimal; import java.util.*; public class Foo { public List<Vo> Service(Vo vo) throws Exception { HashMap<Integer, Object> param = null; ArrayList<HashMap<String, Object>> getRows = null; HashMap<String, Object> row = null; Vo Vo = null; try { List<Vo> list = new ArrayList<Vo>(); if (Vo != null) { param = new HashMap(); if (Vo.getCode() != null) { param.put
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 72026178 โ€บ arraylist-java-lang-outofmemoryerror-java-heap-space
collections - ArrayList - java.lang.OutOfMemoryError: Java heap space - Stack Overflow
@ะ”ะถะตะนะบะœะพั€ะณะฐะฝ instead of reading all data [millions of records] at once, you form a batch of data [it's essentially grouping data in certain size for example 100] and write and repeat the same process until the whole data you need. How are you fetching data ? If you're using spring boot there is spring boot batch processing. Look around in documentation you'll find it. ... An ArrayList with a million objects consumes less than 6MB or maybe 12MB if youโ€™re using flat 64 bit pointers.
๐ŸŒ
Last9
last9.io โ€บ blog โ€บ java-lang-outofmemoryerror
Java OutOfMemoryError: Causes, Fixes & Heap Space Tuning | Last9
February 19, 2026 - For example, LinkedList has different memory characteristics than ArrayList. // ArrayList stores everything in a contiguous array ยท // Good for random access, but expensive for frequent insertions ... For better observability in your Java applications, check out this guide on getting started with the OpenTelemetry Java SDK. Letโ€™s look at some patterns that frequently cause these errors:
Find elsewhere
๐ŸŒ
Reddit
reddit.com โ€บ r/learnprogramming โ€บ [java] trouble adding an object to an arraylist
r/learnprogramming on Reddit: [Java] Trouble adding an object to an Arraylist
April 21, 2015 -

Hi, I'm doing some homework where I have to make a list of student objects and perform certain operations to them, and I need to have two classes, one using an Array and one using an ArrayList. My issue I'm having is I am inserting an object into the Arraylist at a specific index, but its throwing an error.

Here is my code:

public void insertStudent(String studentName, String newName, int q1, int q2, int q3, int q4, int q5) {
        Student newStudent = new Student(newName, q1, q2, q3, q4, q5); //Creates the new student using the given values
        for (int i = 0; i < myClass.size(); i++) //Goes through the list of students myClass
            if (myClass.get(i).name.equals(studentName)) //Checks if the student has the name requested to replace
            {
                myClass.add(i, newStudent);
            }

and this is the error I'm getting:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:475)
	at TestStudent2.insertStudent(TestStudent2.java:42)
	at studentTester.main(studentTester.java:15)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

I'm honestly confused why I'm getting this, when I comment out

myClass.add(i, newStudent); 

I don't get the error, but it looks to me like it should work. Any help would be appreciated.

For what it's worth this is the code I used in the Array portion of the assignment, it works fine.

public void insertStudent(String studentName, String newName, int q1, int q2, int q3, int q4, int q5) {
        Student newStudent = new Student(newName, q1, q2, q3, q4, q5); //Creates the new student using the given values
        Student[] tempClass = new Student[myClass.length + 1];
        boolean t = false;
        for (int i = 0; i < myClass.length; i++)
            if (!myClass[i].name.equals(studentName) && !t)
                tempClass[i] = myClass[i];
            else if (myClass[i].name.equals(studentName)) {
                t = true;
                tempClass[i] = newStudent;
            } else if (t)
                tempClass[i] = myClass[i - 1];
        tempClass[tempClass.length - 1] = myClass[myClass.length - 1];
        myClass = tempClass;
    }

Also here are Pastebins for the entire project if you need some context.

Student.java

TestStudent.java (Using an Array)

TestStudent2.java (Using an ArrayList, the class with the issue)

studentTester.java (My tester class)

Top answer
1 of 2
3
You have an infinite loop occurring. When you see a name match, you insert a new student record into that index. This shifts the record you matched one to the right. When the ArrayList moves onto the next index, you see the previous record again and again insert, causing an infinite loop. Or to make it more clear, given a list: [Alice][Bob][John] and a new student Bob: [Alice][Bob][John] //Find a match [Alice][Bob][Bob][John] //Insert a new Bob into Index 1, prev Bob becomes Index 2 [Alice][Bob][Bob][John] //Finds a match with the shifted record [Alice][Bob][Bob][Bob][John] //Insert a new Bob into Index 2 Repeat until you run out of memory
2 of 2
2
public void insertStudent(String studentName, String newName, int q1, int q2, int q3, int q4, int q5) { Student newStudent = new Student(newName, q1, q2, q3, q4, q5); //Creates the new student using the given values for (int i = 0; i < myClass.size(); i++) //Goes through the list of students myClass if (myClass.get(i).name.equals(studentName)) //Checks if the student has the name requested to replace { myClass.add(i, newStudent); } Imagine that your "myClass" list contains students with the following names: Alice Bob Carol And you wanted to insert a student named "Bob". Here's what that code would do: i = 0 i is less than myClass.size() (3), let's execute the loop body The name of the student at index 0 does not equal "Bob"; do nothing. i= 1 i is less than myClass.size() (3), let's execute the loop body The name of the student at index 1 equals "Bob"; let's insert "Bob" at index 1. The list now looks like: Alice, Bob, Bob, Carol i = 2 i is less than myClass.size() (4), let's execute the loop body The name of the student at index 2 equals "Bob"; let's insert "Bob" at index 2. The list now looks like: Alice, Bob, Bob, Bob, Carol i = 3 i is less than myClass.size() (5), let's execute the loop body The name of the student at index 3 equals "Bob"; let's insert "Bob" at index 3. The list now looks like: Alice, Bob, Bob, Bob, Bob, Carol Repeat forever... Hopefully you can see where this is going. If it finds a student with the same name, it's going to keep looping forever, adding the new person object at each index. As the list gets bigger and bigger, it requires more and more memory; until you get an OutOfMemoryError. You probably want to add a break statement after calling myClass.add(i, newStudent), to exit out of the loop.
Top answer
1 of 3
3

Look at your loop:

while(j<campos.length){
    nombres_reuniones.add(campos[j]);
}

How do you anticipate that ever finishing? You don't modify j. Given that you don't make any change to j after declaring it and assigning it a value of 0 right at the start, it would be much clearer as:

for (int j = 0; j < campos.length; j++) {
    nombres_reuniones.add(campos[j]);
}

Or better:

for (String item : campos) {
    nombres_reuniones.add(item);
}

Or even simpler:

nombres_reunions.addAll(Arrays.asList(campos));

Additionally, your earlier code can be simpler. Look at this:

String aux2 = null;
aux2 = aux.replace("[", "");
aux2= aux2.replace("]", "");

Why bother assigning aux2 an initial value of null which you then immediately overwrite? Additionally, you can easily chain the method calls. It would be neater as:

String aux2 = aux.replace("[", "").replace("]", "");

And in fact, you can just chain the whole of the string manipulation together from start to finish:

String[] campos = jsonReuniones.getString("nombres")
                               .replace("[", "")
                               .replace("]", "")
                               .split(",");
nombres_reunions.addAll(Arrays.asList(campos));

(I'd stop there, rather than inlining even that expression...)

2 of 3
3

You're not advancing the loop:

while (j < campos.length) {
    nombres_reuniones.add(campos[j]);
    j++; // without this, you'll loop forever!
}

What's happening is that you're adding an infinite amount of "campos" to the ArrayList, exhausting all the memory available to your program in the process.

Remember: a loop's condition must be false at some point for the loop to end. If you forget to advance the loop (in this case, by incrementing the j variable) the condition will always be true and the loop will never exit, therefore creating an infinite loop.

๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 57057913 โ€บ java-lang-outofmemoryerror-on-adding-element-in-arraylist
android - java.lang.OutOfMemoryError on adding element in arraylist - Stack Overflow
Reading file names from the device and add them into ArrayList for handling the same files name but add method of ArrayList throwing exception. CopyFatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 55380616 byte allocation with 25165824 free bytes and 25MB until OOM, max allowed footprint 534834552, growth limit 536870912 at java.util.Arrays.copyOf + 3139(Arrays.java:3139) at java.util.Arrays.copyOf + 3109(Arrays.java:3109) at java.util.ArrayList.grow + 275(ArrayList.java:275) at java.util.ArrayList.ensureExplicitCapacity + 249(ArrayList.java:249) at java.util.ArrayList.ensureCapacityInternal + 241(ArrayList.java:241) at java.util.ArrayList.add + 467(ArrayList.java:467)
Top answer
1 of 3
4

You are trying to stuff a file with 468,000 lines into 5G of memory, and are running out of memory.

The data structure isn't the problem.

You need to change your approach and not do that. Process chunks of the file at a time, only extract the data you need, etc.

2 of 3
1

Inserting somewhere within an ArrayList won't give you amortized constant time, as the list will have to be copied internally - this will only work as long as you insert at the end.

Besides, when the ArrayList has to grow, it will calculate the new size by

  int newCapacity = (oldCapacity * 3)/2 + 1;

which could waste huge amounts of memory in your case - it would be more efficient to use custom-sized String-arrays instead of the list (or call at least trimToSize() once you're done reading a column).

As long as you're only needing a few columns per time, I'd suggest to store each column in a separate file, which you can load/write on demand - if they'll only contain strings, you could think of some easy-readable binary format and use DataOutputStream and -InputStream, for instance. Inserting a column would simply become a file renaming operation... You could also add some caching, to keep the most recent or most often used columns in memory (Search for java.util.LinkedHashMap to get an idea of a simple LFU-Cache). Don't use a database if you don't need transactions or such, don't store such data with in a verbose format like XML - you'd get a huge performance loss otherwise.

Finally, I'd think about the content of the matrix, as strings can become pretty huge: Do you really need them as strings, or can you create a less memory consuming representation of them? For instance, if you'd only have 60.000 different strings, you could create a mapping between them and a short, and work with the shorts in memory.

๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 29855991 โ€บ java-lang-outofmemoryerror-at-java-util-arraylist-add
android - java.lang.OutOfMemoryError at java.util.ArrayList.add - Stack Overflow
Load 50 items from your file and if user want to load more data than load next 50 items also override outofMemory in your activity or fragment for safe side, but best approach should be like says if your list contains more than 200 items than remove 1st 50 items and than add new items so you will maintain max 200 items in your list, other safe checks like start or end of file, list size should be consider by doing this you will not get out of memory exception ... Thanks, I was getting an error and I know why I'm getting now.
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 40640736 โ€บ adding-object-to-arraylist-gives-outofmemory-in-android
java - Adding object to arraylist gives outofmemory in android - Stack Overflow
public static ArrayList personData = new ArrayList(); On running the above code I get the OutOfMemory error in Android. ... 16 11:21:28.230 20236-20236/com.app.congress.congressapp E/AndroidRuntime: FATAL EXCEPTION: main Process: com.app.congress.congressapp, PID: 20236 java.lang.OutOfMemoryError: Failed to allocate a 69748 byte allocation with 54912 free bytes and 53KB until OOM at java.util.ArrayList.add(ArrayList.java:118) at com.app.congress.congressapp.ByState$GetAllStates.onPostExecute(ByState.java:112) at com.app.congress.congressapp.ByState$GetAllStates.onPostExecute(ByState.java:49) a