Hi Carl,

A "product" JVM will tell you when EA prevented a heap allocation if you 
enable LogCompilation with -XX:+UnlockDiagnosticVMOptions 
-XX:+LogCompilation.

The output looks something like:

<eliminate_allocation type='878'>
    <jvms method='871' bci='47'/>
</eliminate_allocation>

You can chase those references manually through the log or use JITWatch ;)

Note that an avoided heap allocation is not the same as a stack allocation 
in other languages. HotSpot has a component called the register allocator 
which will decide best where to put the fields. Preferably in CPU registers 
or otherwise onto the stack (known as a stack spill)*

* = VM experts are cringing right now at this explanation ;)

If LogCompilation doesn't contain those eliminate_allocation tags for your 
allocation then assume it was heap allocated.

You can also look at the GC logs with and without the switch 
-XX:-DoEscapeAnalysis if you want to see the effect of disabling the EA 
phase.

If you want a lot more detail on the EA process then you can build a debug 
VM and use the switches:

-XX:+PrintEscapeAnalysis
-XX:+PrintEliminateAllocations

Fun fact: HotSpot won't eliminate allocations for arrays of more than 64 
elements. Control this with -XX:EliminateAllocationArraySizeLimit=n

Cheers

Chris
@chriswhocodes


On Thursday, 25 January 2018 23:22:35 UTC, Carl Mastrangelo wrote:
>
> Interesting tool, I'll try it on some of my code.    
>
> I think that onebyte doesn't escape because I also am the implementer of 
> the other read() overloads.   I was pointing out that implementing the 
> single byte read could be implemented in terms of the multi byte read.  
>  However, it would be unpleasant if it actually allocated memory to do the 
> read.   If onebyte can be allocated on the stack, how do I know it actually 
> is?  (or better yet, not allocated at all)
>
> On Thu, Jan 25, 2018 at 2:49 PM, Chris Newland <[email protected] 
> <javascript:>> wrote:
>
>> Hi Carl,
>>
>> HotSpot's LogCompilation output (enable with 
>> -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation) does contain 
>> information about eliminated allocations (and also elided locks) from EA 
>> but it's tricky to read by eye.
>>
>> JITWatch (https://github.com/AdoptOpenJDK/jitwatch) is a free 
>> open-source tool (disclaimer: I'm the author) that can highlight heap 
>> allocations which were avoided due to the JIT's EA. I made a video on how 
>> to use this feature: https://www.youtube.com/watch?v=LK1Ain1JDlQ
>>
>> Kris Mok and Vladimir Ivanov (HotSpot experts) gave some great info on 
>> how OSR compilation works including variable scope: 
>> https://github.com/AdoptOpenJDK/jitwatch/wiki/Understanding-the-On-Stack-Replacement-(OSR)-optimisation-in-the-HotSpot-C1-compiler
>>
>> In your example below, why do you think the array 'onebyte' doesn't 
>> escape? I can see it passed as a parameter to method read(byte[], int, 
>> int). If that read method is not inlined (inlining is attempted before EA 
>> is applied) then this would be classed as an ArgEscape (object escapes by 
>> passing it as an argument to another method) and could not benefit from 
>> avoiding the heap allocation.
>>
>> Cheers,
>>
>> Chris
>> @chriswhocodes
>>
>>
>> On Thursday, 25 January 2018 19:48:59 UTC, Carl Mastrangelo wrote:
>>>
>>> That's pretty cool.    I'm curious: Does -Xcomp work because it can show 
>>> the variable doesn't escape, or because of deadcode elimination?   For 
>>> example, when implementing an InputStream, one way to implement read would 
>>> be:
>>>
>>>     @Override
>>>     public int read() {
>>>       byte[] onebyte = new byte[1];
>>>       int ret = read(onebyte, 0, 1);
>>>       if (ret == -1) {
>>>         return -1;
>>>       }
>>>       return 0xFF & onebyte[0];
>>>     }
>>>
>>> How can I tell that the compiler knows onebyte array doesn't escape? 
>>>
>>>
>>>
>>> On Thu, Jan 25, 2018 at 12:13 AM, Aleksey Shipilev <
>>> [email protected]> wrote:
>>>
>>>> On 01/25/2018 03:44 AM, 'Carl Mastrangelo' via mechanical-sympathy 
>>>> wrote:
>>>> > Consider the following code:
>>>> >
>>>> > public class Test {
>>>> >   static volatile Integer discard;
>>>> >   public static void main(String [] args) throws InterruptedException 
>>>> {
>>>> >     printMemory();
>>>> >     System.gc();
>>>> >     printMemory();
>>>> >     int iterations = 1000;
>>>> >     int[] vals = new int[100_000_000];
>>>> >     while (args.length == 0) {
>>>> >       printMemory();
>>>> >       System.gc();
>>>> >       Thread.sleep(200);
>>>> >       discard = iterations++;
>>>> >     }
>>>> >   }
>>>> >
>>>> >   private static void printMemory() {
>>>> >     System.out.println(Runtime.getRuntime().totalMemory() - 
>>>> Runtime.getRuntime().freeMemory());
>>>> >   }
>>>> > }
>>>> >
>>>> > I am surprised to see the memory used by this code starts at about 
>>>> 200MB, goes up to 600MB, but
>>>> > never seems to go back down.  The large int array accounts for the 
>>>> memory usage jump, but it never
>>>> > seems to be garbage collected.  Why?   The variable is never read 
>>>> after it is allocated.  It cannot
>>>> > be reordered by the compiler to be after the while loop, because I 
>>>> can see the memory jump.  I am
>>>> > intentionally allocating memory in the loop by boxing the integer.  
>>>> Enabling +PrintCompilation and
>>>> > PrintInlining never shows main() being inlined; perhaps it is not 
>>>> being compiled?
>>>>
>>>> This is not escape analysis. It is more about compiler able to figure 
>>>> out the reachability of local
>>>> variable, and let GC act:
>>>>   https://shipilev.net/jvm-anatomy-park/8-local-var-reachability/
>>>>
>>>> It is predicated on the condition that method is actually compiled and 
>>>> optimized accordingly. OSR
>>>> would not cut it here, I think, because the OSR version of the method 
>>>> would still treat that
>>>> variable alive.
>>>>
>>>> $ java Test
>>>> 10548688
>>>> 260648
>>>> 410809368
>>>> 410673344
>>>> 400260544
>>>> 400260544
>>>> 400260544
>>>> 400260544
>>>> 400260544
>>>> 400260544
>>>>
>>>> It changes if you compile the method before entering it:
>>>>
>>>> $ java -Xcomp Test
>>>> 73841024
>>>> 296240
>>>> 421393656
>>>> 10580272
>>>> 10580608
>>>> 10580608
>>>> 10580608
>>>> 10580608
>>>>
>>>> Thanks,
>>>> -Aleksey
>>>>
>>>> --
>>>> You received this message because you are subscribed to a topic in the 
>>>> Google Groups "mechanical-sympathy" group.
>>>> To unsubscribe from this topic, visit 
>>>> https://groups.google.com/d/topic/mechanical-sympathy/hj5VaYIoNiE/unsubscribe
>>>> .
>>>> To unsubscribe from this group and all its topics, send an email to 
>>>> [email protected].
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>>
>>> -- 
>> You received this message because you are subscribed to a topic in the 
>> Google Groups "mechanical-sympathy" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/mechanical-sympathy/hj5VaYIoNiE/unsubscribe
>> .
>> To unsubscribe from this group and all its topics, send an email to 
>> [email protected] <javascript:>.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"mechanical-sympathy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to