This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
I have an arraylist which will hold nearly 30,000 elements. When I ran the java program it is throwing "java/lang/OutOfMemoryError". I have changed heap size to 1GB then the job worked fine after sometime again it throwed the same error. Please help me how can I get rid of this.
Also revisit the code design for your use case. Do you really need to hold 30000 objects for the processing at the same time.You can sub-task the processing based on your actual use case.serializing is one way to do it.
William Brogden wrote:The default initial size is 10 - just for fun calculate the number of double/enlarge cycles to get to 30,000!
Thats right, grossly inefficient and makes lots of memory chewing objects.
I'm not sure it is that clear-cut.
It would take some 12 reallocations to grow from 10 to 30,000 capacity according to the parameters you've specified. But the ArrayList actually grows by 1.5, not 2 every time, so it will be some 20 reallocations, and it will allocate three times the resulting capacity in the process. Two third of the memory will be freed, of course, and eventually garbage collected. It will amount to some 300 KB of memory in our case (assuming 32bit JVM, in 64 bit JVM it could be two times as much, unless the JVM performed some tricks to decrease the size of a pointer).
In my experience the growing process is pretty fast. Memory allocation is really, really fast in Java (took me a long time to start believing it ). Copying the old array to the new is also pretty fast - it's even done by a native method.
So, the benefits will not really be measurable in a profiler in most applications. But, there can be downsides!
If the needed capacity of the list is only being guessed at and somehow hardcoded into the code, it may easily happen that the guess will become incorrect as the code evolves. If the guess is smaller than the actual need, no harm is done and even some time/memory (update: it's more complicated with memory) is still saved (compared to using the default capacity). But I've experienced changes in code that made my guesses absurdly exaggerated. 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.
I've discovered this problem in my code some time ago, and I've found I'm not reliably able to review and update all relevant capacity guesses after making changes to the application, I've stopped specifying the capacity in most cases. I still specify the capacity when I'm creating a collection by processing another existing collection whose size can be queries and I expect to transfer most items over. I would also specify the capacity if I was expecting the list to be so large that it would occupy significant portion of the memory (so staring at least at a million), but I didn't have such a need in production code yet. Nowadays I believe that striving to always specify the capacity is actually an example of premature optimization.
Instead create your initial ArrayList slightly larger than you will ever need - much faster and easier on memory.
This is the key point. If I could always make sure that the specified capacity will be at most slightly larger, everything would be neat and dandy. But I found it surprisingly hard and time-consuming making sure it is so.