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.