Strange OutOfMemory Exception

H

Hans.Deutsch

Hi,

The following code produces an "OutOfMemoryError: Java heap space"-
Exception:

class test{
public static void main(String[] args)
{
boolean[][][] Matrix=new boolean[31125][1632][2];
}
}

This array should have a size of about 12Mb. I even get the error when
i start it with
"-Xmx30M". With "-Xmx400M" it takes quite a while and steadily fills
up my complete memory.

I use version 1.5.0_10 and debian.

I'd appreciate any hint, cause i'm really clueless about this thing.

Thanks!
 
L

Lew

Hi,

The following code produces an "OutOfMemoryError: Java heap space"-
Exception:

class test{
public static void main(String[] args)
{
boolean[][][] Matrix=new boolean[31125][1632][2];

Variable names should start with a lower-case letter.
}
}

This array should have a size of about 12Mb. I even get the error when

My rough calculations indicate that that array would occupy about 100 MB,
assuming a boolean occupies one byte.

31125 * 1632 * 2 == 101592000

Of course, it's possible that a boolean occupies an entire int, which would
make that array occupy about 400 MB.

From said:
When a compiler translates Java source code into bytecodes, it uses ints or bytes to represent booleans.

i start it with
"-Xmx30M". With "-Xmx400M" it takes quite a while and steadily fills
up my complete memory.

Is there any other code in your program? Could it use memory? Perhaps the
other code is using more memory than even the 100 MB or 400 MB boolean array.
 
A

Andrew Thompson

The following code produces an "OutOfMemoryError: Java heap space" ..
boolean[][][] Matrix=new boolean[31125][1632][2];

By my calculations, that is a total of 101,592,000 elements.
This array should have a size of about 12Mb.

How do you figure that? Even at 1 byte per
boolean, I am seeing it as around 100 meg.

In researching this, I saw advice to use a
BitSet, if size is a problem.

HTH

--
Andrew Thompson
http://www.athompson.info/andrew/

Message posted via JavaKB.com
http://www.javakb.com/Uwe/Forums.aspx/java-general/200704/1
 
G

Gordon Beaton

The following code produces an "OutOfMemoryError: Java heap space"-
Exception:

class test{
public static void main(String[] args)
{
boolean[][][] Matrix=new boolean[31125][1632][2];
}
}

This array should have a size of about 12Mb. I even get the error
when i start it with "-Xmx30M". With "-Xmx400M" it takes quite a
while and steadily fills up my complete memory.

Where does 12 Mb (Mbit?) come from?

Each of the 31125 elements in the outermost array holds a reference to
a 2D array.

Each of those arrays holds 1632 references to an array of boolean, so
there are about 50 million references, and 50 million 1D arrays here.

Finally, each 1D array holds 2 booleans.

Assuming that a typical object (arrays are objects too) takes, say, 16
bytes, and a reference takes 4 bytes, then you need more than a
gigabyte just to hold all the references and arrays, plus whatever
space is needed by 100 million booleans.

/gordon (hoping I've done the math right)

--
 
T

Tom Hawtin

boolean[][][] Matrix=new boolean[31125][1632][2];
This array should have a size of about 12Mb. I even get the error when


Two things to bare in mind. One is that in order to avoid word tear,
booleans will typically take up at least a byte each (interleaved writes
from threads to adjacent memory should not interfere). Secondly, there
is no multidimensional arrays in Java, as such. What you have here is an
array of arrays of arrays, which could be quite a lot of objects. Each
object will have a certain overhead.

How to fix? Use a single array of byte/short/char/int/long and wrap in
an object that munges indexes. If you require threaded access, use
java.util.concurrent.atomic.AtomicLongArray/AtomicIntegerArray.

Tom Hawtin
 
L

Lew

Gordon said:
Each of the 31125 elements in the outermost array holds a reference to
a 2D array.

Each of those arrays holds 1632 references to an array of boolean, so
there are about 50 million references, and 50 million 1D arrays here.

Finally, each 1D array holds 2 booleans.

Assuming that a typical object (arrays are objects too) takes, say, 16
bytes, and a reference takes 4 bytes, then you need more than a
gigabyte just to hold all the references and arrays, plus whatever
space is needed by 100 million booleans.

/gordon (hoping I've done the math right)

Damn, I forgot about the references. Just the space for the booleans is
enough to kill the heap, but the reference overhead is so much larger than that.

(31125 * 4) * (16 * 1632 * 4) * 100e6 * 1 == roughly 3e16 bytes
(30 petabytes).

That'd wreak hell on my swap space, too.
 
C

Chris Uppal

The following code produces an "OutOfMemoryError: Java heap space"-
Exception:

class test{
public static void main(String[] args)
{
boolean[][][] Matrix=new boolean[31125][1632][2];
}
}

Let's break down how that uses space. You have an array of 31125 references to
byte[][] arrays. Each of those byte[][] arrays holds 1632 references to byte[]
arrays. Each if those 31125 * 1632 byte[] arrays holds 2 booleans. The
details of how much space each array requires is dependent on the JVM
implementation, but I'll assume a current 32-bit JVM from Sun.

First off, consider the 31125*1632 byte[] arrays. Each of those arrays holds 2
Booleans. Typically a JVM will represent Booleans (in arrays) as 1 byte each.
In addition, each array is a full object, and so it has an 8-byte object header
(which is not visible from Java code) and a 4-byte record of how big it is. So
that makes a total of
31125 * 1632 * (12 + 2) == 711144000
bytes. I.e, about 700 MBytes.

That's just for the byte[] arrays themselves. There are also 31125 arrays
which hold references /to/ those arrays (the byte[][] arrays). Each of those
has 1632 4-byte slots, plus the 12 bytes of object header/size, making (1632 *
4) + 12 bytes each. So these total
31125 * ((1632 * 4) + 12) == 203557500
bytes. I.e. around 200 MBytes.

Lastly there's the byte[][][] array itself. That has 31125 slots of 4 bytes
each, plus the usual 12-byte array header, making
(31125*4) + 12 == 124512
bytes. Pretty trivial ;-)

So the sum total is:
711144000 + 203557500 + 124512 == 914826012
bytes. Or nearly a Gigabyte.

So you run out of space...


The simplest way to avoid this blow-up is to use a single byte instead of each
array of two Booleans (plus some bit-twiddling). That wastes 6 out of the 8
possible bits, but it is relatively simple. If you do that then the array
creation expression would be:
byte[][] packedMatrix = new byte[31125][1632];
which takes up a /lot/ less space. In fact there would be an array of 31125
references to byte[] arrays (making 12452 bytes, as above), plus 31125 byte[]
arrays, each of which held 1632 bytes. So they would total:
31125 * (1632 + 12) == 51169500
bytes. So the whole thing takes around 52 MBytes.

If you are willing to do a bit more work, then you could represent the whole
structure as a single array of
31125 * 1632 * 2
bits, where you pack each 32 bits into an int. The allocation expression would
be

int[] packedMatrix = new int[31125*1632*2/32];
(ignoring rounding). And that would take up only 12 MBytes, but the code to
access each bit will be a little more complicated (but faster as well as more
space efficient).

In fact you could probably use a java.util.BitSet instead of an int[] array,
and let Java do some of the work for you:
BitSet packedMatrix = new BitSet(31125*1632*2);
You'd still have to do /some/ work yourself to convert three-level indexes into
integer offsets, but at least the BitSet would look after the bit-twiddling
(which not everybody is comfortable with). On the other hand, it might be
slower than a hand-coded implementation. If that matters to you then try it
both ways and see which is quicker.

-- chris
 
G

Gordon Beaton

Damn, I forgot about the references. Just the space for the booleans
is enough to kill the heap, but the reference overhead is so much
larger than that.

(31125 * 4) * (16 * 1632 * 4) * 100e6 * 1 == roughly 3e16 bytes
(30 petabytes).

That'd wreak hell on my swap space, too.

I don't think it's quite that bad...

There are (31125 * 1632 * 2) booleans, or about 100 million of them.
Pretending that we need 1 byte for each (they aren't objects), that's
100 MB.

There are (31125 * 1632) or just over 50 million 1D arrays, and as
many references to them. So 50M x 20 bytes is about 1 GB.

There are 31125 2D arrays, and again as many references. So 31125 x 20
bytes is about 600 KB.

There's one 3D array, so 20 bytes.

In all, that makes 100 MB + 1 GB + 600 KB + 20 B, or about 1.16 GB.

/gordon

--
 
H

Hans.Deutsch

Thank you very much for all the answers.
I assumed that a boolean value is stored in only one bit.
I guess i'll try the BitSet thing then.
Thanks again!
 
E

Eric Sosman

Hi,

The following code produces an "OutOfMemoryError: Java heap space"-
Exception:

class test{
public static void main(String[] args)
{
boolean[][][] Matrix=new boolean[31125][1632][2];
}
}

This array should have a size of about 12Mb.

.... for values of "12" within epsilon of 97.
 
H

Hans.Deutsch

Thanks for all your answers.
I assumed that that a boolean only takes one bit and i didnt know
about all those array of array overhead stuff.
I tried it with BitSet and now it works fine.
Thanks again
 
H

Hans.Deutsch

Thanks for all your answers.
I assumed that that a boolean only takes one bit and i didnt know
about all those array of array overhead stuff.
I tried it with BitSet and now it works fine.
Thanks again
 
C

Chris Uppal

Gordon said:
There are (31125 * 1632 * 2) booleans, or about 100 million of them.
Pretending that we need 1 byte for each (they aren't objects), that's
100 MB.

Unless, of course, someone decides to use an ArrayList<boolean> to hold them
;-)

-- chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,830
Latest member
HeleneMull

Latest Threads

Top