6

For those eager to flag this as duplicate, this question is not related to any of the questions like:

How to calculate Java array's memory size?

Memory size of Java 32-bit system int[] arrays


In Java when an array of primitive int is created:

int[] arr = new int[1000];

Does the JVM allocate memory for the entire array length * 4 bytes, i.e. 4000 bytes after the above statement? Let's not bother about constant overheads like headers etc.

My understanding is that in case of primitive numeric types, e.g. int, double etc., the default value '0' is also a valid value, hence needs memory. In effect, full required memory must be allocated at the time of such declarations.

How could I verify it?

20
  • 12
    Don't just state that it isn't duplicative, explain why. (Note that sparse allocations exist -- some operating systems allow virtual memory to be allocated without any physical memory backing it until contents are actually added; so it's very possible that this is undefined behavior and JVMs that today actually allocate physical memory pages could stop doing so without notice in future versions, making this a question that there doesn't exist an enforced-by-specification answer to at all) Commented Nov 8, 2024 at 12:26
  • 7
    An int value of 0 is still a 32-bit value. Commented Nov 8, 2024 at 12:30
  • 1
    This, how calculate java array memory usage may contain the information that you want. Also, check out Array of objects in Memory Commented Nov 8, 2024 at 12:39
  • 1
    In particular, to see if the technique i referenced is in use, watch the page fault counter for your process the first time you write to the previously-empty array. If it doesn't increment that's firm proof. (Do make sure you allocated enough memory for any of these techniques to apply, but not so much as to force content to be paged out). Commented Nov 8, 2024 at 13:08
  • 3
    Post your additional details as edits to your Question, not Comments. Commented Nov 8, 2024 at 16:58

3 Answers 3

6

Let’s see

public class Test {
    public static void main(String[] args) {
        for(int i = 0; i < Integer.MAX_VALUE; i++) {
            if(test(i) != i + 0x123)
                throw new AssertionError();
        }
    }
  
    static int test(int someArg) {
        int[] arr = new int[1000];
        arr[42] = someArg;
        return arr[42] + 0x123;
    }
}
jdk-17\bin\javac -d %tmp% src\Test.java
jdk-17\bin\java -XX:CompileCommand=print,Test.test -cp %tmp% Test
…
============================= C2-compiled nmethod ==============================
----------------------------------- Assembly -----------------------------------

…

--------------------------------------------------------------------------------

[Verified Entry Point]
  # {method} {0x0000020061400350} 'test' '(I)I' in 'Test'
  # parm0:    rdx       = int
  #           [sp+0x20]  (sp of caller)
  0x000002004e6e2f00:   sub    $0x18,%rsp
  0x000002004e6e2f07:   mov    %rbp,0x10(%rsp)
  0x000002004e6e2f0c:   mov    %edx,%eax
  0x000002004e6e2f0e:   add    $0x123,%eax
  0x000002004e6e2f14:   add    $0x10,%rsp
  0x000002004e6e2f18:   pop    %rbp
  0x000002004e6e2f19:   cmp    0x340(%r15),%rsp             ;   {poll_return}
  0x000002004e6e2f20:   ja     0x000002004e6e2f27
  0x000002004e6e2f26:   ret
  0x000002004e6e2f27:   movabs $0x2004e6e2f19,%r10          ;   {internal_word}
  0x000002004e6e2f31:   mov    %r10,0x358(%r15)
  0x000002004e6e2f38:   jmp    0x0000020046c63400           ;   {runtime_call SafepointBlob}
  0x000002004e6e2f3d:   hlt
  0x000002004e6e2f3e:   hlt
  0x000002004e6e2f3f:   hlt
[Exception Handler]
  0x000002004e6e2f40:   jmp    0x0000020046d05480           ;   {no_reloc}
[Deopt Handler Code]
  0x000002004e6e2f45:   call   0x000002004e6e2f4a
  0x000002004e6e2f4a:   subq   $0x5,(%rsp)
  0x000002004e6e2f4f:   jmp    0x0000020046c626a0           ;   {runtime_call DeoptimizationBlob}
  0x000002004e6e2f54:   hlt
  0x000002004e6e2f55:   hlt
  0x000002004e6e2f56:   hlt
  0x000002004e6e2f57:   hlt
--------------------------------------------------------------------------------

As we can see, aside from the instructions dealing with the method invocation itself (i.e. stack manipulation), the C2 generated code for the test method consists of the two instructions, mov %edx,%eax and add $0x123,%eax. No array allocation, no array zeroing.

This is, of course, the most extreme scenario. But it demonstrates, that there is no requirement to do what has been written literally, as long as the resulting behavior is compatible.


Besides that, the term “allocation” is ambiguous. It implies changing some data structure to record that a particular region of memory is not available for other purposes. But there are differences in who shares this structure and hence, the same point of view regarding what is allocated.

Small allocations are usually done in a TLAB which is dedicated to a single thread. So allocating a small array in a TLAB only makes a difference to that thread. From the other threads’ point of view, the memory of that TLAB wasn’t available anyway. But even when a new TLAB is allocated from the heap memory shared by all threads, it’s memory that is considered already reserved to the JVM process from the operating system’s point of view. Only when the JVM expands or shrinks the entire heap memory, it will affect what the operating system reserves to the JVM (which is what may have an impact on other processes).

But even when memory is allocated from the operating system, it doesn’t have to be backed by physical memory. The operating system may postpone this operation to the point where the first actual write operation happens. Up to that point, the memory may still be considered all-zero-filled, which is the typical default, and the system does not need actual memory for an all-zero-filled region.

Sign up to request clarification or add additional context in comments.

Comments

0

Yes, the JVM does allocate all memory at once.

9 Comments

Virtual memory only, or physical memory as well? Is this defined by specification or implementation?
@CharlesDuffy The host Operating System (OS) manages virtual memory, not the Java Virtual Machine (JVM). Like any other app (process), the JVM always believes in the illusion that it operates upon physical memory (RAM).
@CharlesDuffy I doubt specification says anything about physical memory. It may run on fairy dust and good wishes as far as specification concerns. And since JVM most probably initialize memory at allocation it will be allocated by OS as well.
@talex, ..."most probably" is something I'm not sure about. It's the easy implementation, sure, but for something like a JVM where there's serious engineering investment into making it fast, it makes sense to recognize corner cases where you can tell the OS to map the whole virtual span to a single zeroed-out page in read-only mode and only allocate real memory when there's an attempt to write to something in that span triggering a page fault.
@CharlesDuffy the HotSpot JVM by default allocates memory for the heap in a way that it is not backed by physical memory until the first actual write occurs. That’s why the -XX:+AlwaysPreTouch option exist, which forces accesses to the memory pages so they are eagerly assigned to physical memory. Usually, filling an array with its default values (zeros) on allocation does work like an access that will make the page backed by physical memory, but as discussed in this article, this initial filling can be eliminated in some cases…
|
-1

Does the JVM allocate memory for the entire array length * 4 bytes, i.e. 4000 bytes after the above statement

Java will do it as you say, and one more thing is that the memory needs to be contiguous. Because the data of arrar is consecutive, it is necessary to fully allocate it when initializing the array, if there is no contiguous memory, out of mem will occur.

Some space will be needed for the array itself, but it's only about 4 to 8 bytes.

For example: I will allocate parking spaces for A to accommodate 100 cars. And allocate parking spaces for B to accommodate 50 cars right behind A.

Even though A may not have all 100 cars yet, I need to know the exact size of each car to accurately calculate the space needed for 100 cars to provide parking for A. The same applies to B for next behind A.

1 Comment

This completely disregards the distinction between virtual and physical memory. Virtual memory for an array needs to be contiguous, but on any 64-bit platform there's an enormous amount of it available; and that virtual memory absolutely does not need to be mapped contiguously into physical memory -- each page of virtual memory can be allocated to a completely different place in physical memory, or not mapped to any physical memory at all (f/e, if swapped out, or backed by mmap'd disk).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.