I have seen almost all of the JVM memory parameters usually in multiples of 256 or a round binary value - e.g. 256m, 512m, 1024m etc. I know, it may be linked to the fact that physical memory (RAM) is usually a binary number, such as 256 MB, 1 GB etc.
My question is does it really help the memory management in anyway if JVM memory is set to a value that is a multiple of 256 or any binary value for that matter? Does it hurt to keep the JVM memory a round decimal value, such as 1000m, instead of 1024m - though I have never seen any JVM using such a value that is considered round in terms of decimal.
The OS would allocate the mentioned memory to JVM when it is launched, so I guess, it is more of a question for the JVM whether it can manage a round decimal memory size (e.g. 1000 MB) efficiently or would there be any shortcomings.
EDIT: I know, we CAN use decimal values for JVM memory, but my question is SHOULD we use decimal values?
EDIT2: For opinions/guesses about JVM being equally efficient of handling every memory size, please share any relevant links that you used for coming to that conclusion. I have seen enough WAR on this topic among fellow developers, but I haven't seen much of concrete reasoning to back either - decimal or binary value.
It is not necessary to use a multiple of 2 for the JVM memory parameters. It is just common use for memory allocation to double the value if the old one isn't enough.
If you increase your assigned memory value in 1MB steps you will have to adjust the value several (hundred) times before the configuration matches you requirements. So it it just more comfortable to double the old value.
This relies on the fact that memory is a cheap ressource in those days.
EDIT:
As you already mentioned it is possible to assign values like 1000 MB or 381 MB. The JVM can handle every memory size that is big enough to host the permGenSpace, the stack and the heap.
It does not matter. There is no special treatment of rounded values.
You can specify the memory size within 1-byte accuracy - JVM itself will round the size up to the value it is comfortable with. E.g. the heap size is rounded to the 2 MB boundary. See my other answer: https://stackoverflow.com/a/24228242/3448419
There is not real requirement those values be a multiplier of 2. It is just a way of use. you can use what ever values there.
-Xms1303m -Xmx2303m -XX:MaxPermSize=256m // my configs
I think it is mainly a way of thinking, something like: I have a 1 GB memory, I will give JVM a half, which is 512 MB.
It is just a way to ensure the size that you specify (as argument) fits to the actual allocated memory, because the machine allocates the memory in blocks of size power of 2.
Related
I'm running Java Visual VM to analyze performance on a Mule app to reduce the amount of memory used. When I look at the heap dump, I see that char[] has a size of over 37 MB, String has a size of a bit over 28 MB.
What I'm not clear on is how the size column accounts for the amount of memory used. In particular, since a String is an abstraction of a char[], I'm wondering if this means that some of that 37 MB of char arrays is also present within the 28 MB of Strings, or if they are allocated separately.
On top of that, I also have a class that I suspect is hogging a great deal of memory and contains several strings, but according to my heap dump, this class only uses 6.5% of the total memory in the heap.
So I guess my question is... If I were to make my custom class more efficient by using fewer String objects, would I see a reduction in the amount of memory reported to be used by Strings and Char[]s, or just for that specific class?
Thanks!
Holger's comment is all I needed...
"The sizes only include the memory for an object itself, not any referenced object (and arrays are objects)."
This alone gives me a much better idea of how I can optimize.
I know that Integers act like interns for the values less than 128 (default) and not for the values more than that. I know that this has been given as an answer many times but I couldn't noticed a place that the reason is asked.
So what I want to know is Why Integers act as interns only for the values less than 128 (default) and not for the values more than that? How does it improve the less memory usage / high performance?
Technically the values are pre-cached when the class is loaded. It is not like String.intern() where a value you created can be returned.
Also the maximum might not be 127, it can be higher if you set it so or use options like -XX:+AggressiveOpts
The default range is likely to be chosen just to be consistent with Byte. Note: the cached values are
Boolean: both values
Byte: all
Character: 0 to 127
Short: -128 to 127
Integer: -128 to 127
Long: -128 to 127
Float and Double: none
BigInteger: -16 to 16 (in HotSpot Java 7)
BigDecimal: 0 to 10 (if you use valueOf(long)) and
0 to 0.000000000000000 (if you use valueOf(long, int)) (in HotSpot Java 7)
The reason it is done is to improve performance and reduce GC pressure.
Creating garbage can fill your cache with garbage, slowing down all your code, it also takes work to create objects and to clean them up. The less work you do the faster and more consistent your program will be.
Here is a good article of the difference it makes http://www.javaspecialists.eu/archive/Issue191.html
Look at it like this:
It is certainly not desirable to cache all Integer values. For, this would mean that when a JVM starts up, it'd have to make more than 4 billion Integer objects which would most likely not fit in the memories of contemporary computers.
Hence, one must decide to cache some smaller number of Integers (if at all). This number should be small enough so that no memory usage or slower startup is noticeable. OTOH, it should cover as most cases as possible. Not having read any study concerning this, but from experience we can say with confidence that very small integers are most often used.
Thus, the decision to cache 128 numbers is completly arbitrary, yet it still makes sense. It could as well be 30 or 300. But certainly not a million.
How does this help performance? Well, it sppeds up autoboxing for small numbers, because one does not have to construct an Integer, but rather pick one from the cache (which is most likely an Integer[128] array) with a single memroy access. At the same time, it is well known that many Integers are short-lived. Use of pre-allocated objects that need not be garbage collected takes away stress from the GC.
I wish to make a large int array that very nearly fills all of the memory available to the JVM. Take this code, for instance:
final int numBuffers = (int) ((runtime.freeMemory() - 200000L) / (BUFFER_SIZE));
System.out.println(runtime.freeMemory());
System.out.println(numBuffers*(BUFFER_SIZE/4)*4);
buffers = new int[numBuffers*(BUFFER_SIZE / 4)];
When run with a heap size of 10M, this throws an OutOfMemoryException, despite the output from the printlns being:
9487176
9273344
I realise the array is going to have some overheads, but not 200k, surely? Why does java fail to allocate memory for something it claims to have enough space for? I have to set that constant that is subtracted to something around 4M before Java will run this (By which time the printlns are looking more like:
9487176
5472256
)
Even more bewilderingly, if I replace buffers with a 2D array:
buffers = new int[numBuffers][BUFFER_SIZE / 4];
Then it runs without complaint using the 200k subtraction shown above - even though the amount of integers being stored is the same in both arrays (And wouldn't the overheads on a 2D array be larger than that of a 1D array, since it's got all those references to other arrays to store).
Any ideas?
The VM will divide the heap memory into different areas (mainly for the garbage collector), so you will run out of memory when you attempt to allocate a single object of nearly the entire heap size.
Also, some memory will already have been used up by the JRE. 200k is nothing with todays memory sizes, and 10M heap is almost unrealistically small for most applications.
The actual overhead of an array is relatively small, on a 32bit VM its 12 bytes IIRC (plus what gets wasted if the size is less than the minimal granularity, which is AFAIK 8 bytes). So in the worst case you have something like 19 bytes overhead per array.
Note that Java has no 2D (multi-dimensional) arrays, it implements this internally as an array of arrays.
In the 2D case, you are allocating more, smaller objects. The memory manager is objecting to the single large object taking up most of the heap. Why this is objectionable is a detail of the garbage collection scheme-- it's probably because something like it can move the smaller objects between generations and the heap won't accomodate moving the single large object around.
This might be due to memory fragmentation and the JVM's inability to allocate an array of that size given the current heap.
Imagine your heap is 10 x long:
xxxxxxxxxx
Then, you allocate an object 0 somehere. This makes your heap look like:
xxxxxxx0xx
Now, you can no longer allocate those 10 x spaces. You can not even allocate 8 xs, despite the fact that available memory is 9 xs.
The fact is that an array of arrays does not suffer from the same problem because it's not contiguous.
EDIT: Please note that the above is a very simplistic view of the problem. When in need of space in the heap, Java's garbage collector will try to collect as much memory as it can and, if really, really necessary, try to compact the heap. However, some objects might not be movable or collectible, creating heap fragmentation and putting you in the above situation.
There are also many other factors that you have to consider, some of which include: memory leaks either in the VM (not very likely) or your application (also not likely for a simple scenario), unreliability of using Runtime.freeMemory() (the GC might run right after the call and the available free memory could change), implementation details of each particular JVM, etc.
The point is, as a rule of thumb, don't always expect to have the full amount of Runtime.freeMemory() available to your application.
I have observed while setting heap size people prefer the values 64,128,256,1024.. . If I give a value in- between these numbers (say 500), won't the JVM accept that value? Why these numbers are important and preferred? Why we also upgrade RAM in this pattern?
Please help me to understand.
JVM will accept any value, no problem with that. Using 2^n values is just a "convention", using others will have no negative effect in practice.
Well, if you think about it this way:
1 byte is 8 bits
1 kb = 1024 bytes
1 mb = 1024 kb
1 gb = 1024 mb
... and so on ...
It's not just 2^n. Things in terms of memory in computing are closely related to the number eight - the number which defines one byte in most modern computers.
The main reason why bits are grouped together is to represent characters. Because of the binary nature of all things computing, ideal 'clumps' of bits come in powers of 2 i.e. 1, 2, 4, 8, 16, 32.... (basically because they can always be divided into smaller equal packages (it also creates shortcuts for storing size, but that's another story)). Obviously 4 bits (nybble in some circles) can give us 2^4 or 16 unique characters. As most alphabets are larger than this, 2^8 (or 256 characters) is a more suitable choice.
Machines exist that have used other length bytes (particularly 7 or 9). This has not really survived mainly because they are not as easy to manipulate. You certainly cannot split an odd number in half, which means if you were to divide bytes, you would have to keep track of the length of the bitstring.
Finally, 8 is also a convenient number, many people (psychologists and the like) claim that the human mind can generally recall only 7-8 things immediately (without playing memory tricks).
If it won't accept the value, check whether you put a megabytes(M or m) or gigabytes(G or g) modifier after the amount.
Example: java -Xms500M -Xmx500M -jar myJavaProgram.jar
Also, take a look at this link.
Why we also upgrade RAM in this pattern.
That is because memory chips / cards / come in sizes that are a power of 2 bytes. And the fundamental reason for that is that it makes the electronics simpler. And simpler means cheaper, more reliable and (probably) faster.
Except non-written convention, it has also performance impact - depending on the the architecture of the machine.
For example if a machine is ternary based, it would work better with a heap size set to a value which is a power of 3.
Admittedly, I could have figured it out through trial and error, but I would also like to know whether or not this number varies and how (computer performance, other data structures present, compiler type, etc.). Thanks!
You will need to increase you JVM heap size if you run out of memory, read this. Nothing you can do if your matrix requires a lot of memory (if there is no memory leaks) other than increasing the heap size.
You can change the size of your matrix as large as you want (but not bigger than the maximum value of integer which is used as index) if you have enough memory. Integer is 32bits so, you have the maximum theoretical limit there.
While the maximum array size is the limited by a 32-bit signed value. i.e. 2^31-1 or about 2 billion, most matrices are implemented as two dimensional arrays so the maximum size is 2 billion * 2 billion. You could use float or double, but if you had a matrix that big your accumulated rounding error would be enormous. ~ 2^62 bits which is more than the accuracy of a double, so you would have to use BigDecimal in any case. Say the each cell took about 128 (2^7) bytes of memory you would need a total of 2^69 bytes or 512 Exa-bytes (32x the theoretical limit of the memory a 64-bit processor can handle)
it also depends upon the memory of your machine and how much memory you allocate for the process using -Xmx.