A few problems that I see:
You synchronize the MyTask
object, which is created separately for each execution. You should synchronize the shared object, preferably the one you are modifying, i.e. The locations
object.
216,000 runs, multiplied by 10,000 returned objects each, multiplied by a minimum of 12 bytes per Integer
object, is about 24 GB of memory. Do you even have such physical memory available on your computer, much less accessible to the JVM?
32-bit JVMs have a heap size limit of less than 2 GB. With a 64-bit JVM, on the other hand, an Integer
object takes up about 16 bytes, which increases memory requirements to more than 30 GB.
With these numbers, it comes OutOfMemoryError
no surprise that you get an OutOfMemoryError
...
PS: If you have such physical memory, and you still think that you are doing the right thing, maybe you should take a look at setting the JVM heap size .
EDIT:
Even with the 25 GB of memory available to the JVM, it can still click it:
Each Integer
object requires 16 bytes on modern 64-bit JVMs.
You will also need an 8-byte link that points to it, no matter what List
implementation you use.
If you use the implementation of a linked list, each record will also have service data of at least 24 bytes for the list entry object.
At best, you can hope to store about 1,000,000,000 Integer
objects in 25 GB - half if you use a linked list. This means that each task cannot produce more than 5,000 (2,500) objects on average without causing errors.
I'm not sure about your specific requirement, but have you thought about returning a more compact object? For example, an int[]
array created from each HashSet
would save at least 4 bytes per result without the overhead of the object container.
EDIT 2:
I just realized that you store HashSet
objects yourself in a list. HashSet
objects use a HashMap
inside, which then uses the HashMap.Entry
object of each record. On a 64-bit JVM, a write object consumes about 40 bytes of memory in addition to the stored object:
The key reference pointing to the Integer
object is 8 bytes.
The reference to the value (always null
in a HashSet) is 8 bytes.
The next record link is 8 bytes.
The hash value is 4 bytes.
The object overhead is 8 bytes.
Filling objects - 4 bytes.
those. for each Integer
object, you need 56 bytes to store in a HashSet
. With a typical HashMap
load HashMap
0.75, you must add another 10 or bytes for the links in the HashMap
array. With 66 bytes per Integer
you can only store about 400,000,000 such objects in 25 GB, without taking into account the rest of your application any other overhead. This is less than 2000 objects per task ...
EDIT 3:
You are better off storing a sorted array of int[]
instead of a HashSet
. This array is searchable in logarithmic time for any arbitrary integer and minimizes memory consumption by up to 4 bytes per number. Given memory I / O, it will also be as fast (or faster) as the HashSet
implementation.
source share