Java 64 bit consumes excessive native memory (c-heap) due to JIT Compilation

Vladimir Kozlov vladimir.kozlov at oracle.com
Mon Aug 27 11:12:28 PDT 2012


Ashish,

I sent webrev for 7148109 fix last week and I am going to push it today:

http://cr.openjdk.java.net/~kvn/7148109/webrev.01

Ashish Saxena wrote:
> Vladimir,
> 
> I tried running the application with the JVM Options you provided and
> 64 MB blocks occurs printing the compilation of methods. However,
> compilation output shows too many methods getting compiled and not a

It is normal, it means you have a lot of hot methods.

> single huge method. I believe global inling is happening here.
> 
> As you pointed out, it could be due to register allocator spilling
> during inlining optimizations during JIT Compilation for particular
> shape of code.
> 
> Observation in support of above reason :
> - 64 MB blocks doesn't occurs with inlining disabled (-XX:-Inline)
> 
> Open questions :
> - Why are all blocks (c-heap) nearly 64 MB in size ? Can you please
> point me to code  .. can't find it in chaitin.cpp ?

RA do several attempts (iterations) to allocate as much live values on registers 
as possible. For each (spill, split) cycle RA allocates few arrays in Split() 
method with size "sizeof(ptr*)*num_blocks*spill_cnt" and does not free resource 
on method exit. If spill_cnt stays about the same for 10 iterations you 
observed, then you will have the same total allocation size.

> - Why this issue doesn't appear on 32 bit JVM ? Are register allocator
> code different for 32 bit JVM. Since 32 bit JVM have half the
> registers compared with 64 bit JVM, register allocator spilling should
> be more prominent in 32 bit JVM.

Two possibilities.

One, most probable, the inlining is different because generated code size is 
different in 32 bit VM (more spills on stack, more instructions for '64 bit' 
integer arithmetic and other). And JIT inlining heuristic avoids inlining of 
method which already have big compiled code. So "deadly" code pattern did not 
happen. You can play with flag -XX:InlineSmallCode=<n> (default is 1000) to see 
if it will affect your compilation. Warning: it is our internal flag which was 
tunned for best performance of most applications. If you change it, it may 
affect your application performance.

An other possibility, RA may be able finish job in one or two iteration because 
only few registers are available (most live values are kept on stack). But then 
you should still see one or two 32Mb blocks allocated in native memory.

> 
> Are there any Java coding guidelines/observations which can help in
> writing code that doesn't trigger register spilling ?

RA will always spill unless a hardware (cpu) has a LOT more registers than x86.
One suggestion would be to not pre-load a value which is used only later and 
does not change in between.

> Similarly are there sample code that can deliberately cause register
> to spill and show excessive memory usage ?

It is a rare case. We never got a small test case.

Regards,
Vladimir

> 
> Thanks and Regards,
> Ashish
> 
> On Fri, Aug 24, 2012 at 12:36 AM, Vladimir Kozlov
> <vladimir.kozlov at oracle.com> wrote:
>> Ashish,
>>
>> It could be related to 7148109. Register Allocator may consume a lot of
>> memory for particular shape of code.
>>
>> You can also check if this memory reservation happens during JIT
>> compilation. Run with "-Xbatch -XX:CICompilerCount=1 -XX:+PrintCompilation".
>> Only one compiler thread will run and it will print which method is
>> compiled. This way you can find which method compilation triggers it if it
>> is really JIT.
>>
>> Regards,
>> Vladimir
>>
>>
>> Ashish Saxena wrote:
>>> These 64 MB blocks are committed and marked dirty and actually using
>>> the RAM.. Hence the conern. As Andrew pointed, may be it is due to
>>> some c-heap allocation specific to 64 bit systems.... but under what
>>> circumstances do these blocks get allocated ? Which JVM Component /
>>> Subcomponent is responsible for these extra memory blocks ?
>>>
>>> Based on test and JVM options I mentioned above, it seems that these
>>> gets allocated whenever JVM gets into JIT mode for the first time (may
>>> be, may be not) ... but which JVM sub component is responsible for
>>> this memory overhead ?
>>>
>>> Thanks,
>>> Ashish
>>>
>>> On Wed, Aug 22, 2012 at 11:07 PM, Andrew Haley <aph at redhat.com> wrote:
>>>> On 08/22/2012 05:36 PM, Vitaly Davidovich wrote:
>>>>> Reserving a 64mb private heap sounds fine on 64bit, but it sounds like
>>>>> that
>>>>> memory is being committed since RSS goes up?
>>>> Maybe, maybe not.  We don't know that those 64M blocks are committed.
>>>> All I'm
>>>> saying is that I have a suspicion that I know what they are.
>>>>
>>>> Andrew.
>>>>


More information about the hotspot-compiler-dev mailing list