2016-09-27 9 views
5

vJUG24 पर, विषयों में से एक JVM performance था।वैरग्स लेने वाली विधि को मोनोमोर्फिक कॉल की श्रृंखला में अनुकूलित क्यों किया जा सकता है, यदि यह स्थैतिक है?

स्लाइड्स here मिल सकते हैं।

उन्होंने एक उदाहरण था:

static void log(Object... args) { 
    for(Object arg : args) { 
     System.out.println(arg); 
    } 
} 

जो के माध्यम से बुलाया गया था (काफी स्लाइड ठीक से नहीं पढ़ सकते हैं, लेकिन यह समान है):

void doSomething() { 
    log("foo", 4, new Object()); 
} 

उन्होंने कहा कि क्योंकि यह एक स्थिर तरीका था , इसे इस तरह इनलाइन करके अनुकूलित किया जा सकता है:

void doSomething() { 
    System.out.println("foo"); 
    System.out.println(new Integer(4).toString()); 
    System.out.println(new Object().toString()); 
} 

यह क्यों महत्वपूर्ण है कि लॉग विधि है इस अनुकूलन को बनाने के लिए जेवीएम के लिए tatic?

+1

आप कैसे सुनिश्चित करना चाहते हैं कि यह विधि 'स्थैतिक' नहीं है तो यह विधि अतिरंजित नहीं हुई है? (और यह 'निजी' या 'अंतिम' नहीं है) – Tom

+0

@ टॉम: जेवीएम * जानता है * क्या एक विधि ओवरराइड हो गई है। अगर हर भारित वर्ग जानता है। – Holger

उत्तर

5

या तो प्रस्तुति बिल्कुल सटीक नहीं थी, या आपको यह सही नहीं मिला।

वास्तव में, जेवीएम इनलाइन गैर-स्थैतिक तरीकों, varargs के साथ भी कर सकते हैं। इसके अलावा, यह कुछ मामलों में संबंधित Object[] सरणी के आवंटन को समाप्त कर सकता है। दुर्भाग्यवश, यह ऐसा नहीं करता है जब एक vararg विधि for लूप का उपयोग कर सरणी पर पुनरावृत्ति करता है।

मैंने सिद्धांत को सत्यापित करने के लिए निम्नलिखित JMH बेंचमार्क बनाया और इसे GC profiler (-prof gc) के साथ चलाया।

package bench; 

import org.openjdk.jmh.annotations.Benchmark; 
import org.openjdk.jmh.infra.Blackhole; 

public class VarArgs { 

    @Benchmark 
    public void inlineNonStatic(Blackhole bh) { 
     inlineNonStaticVA(bh, "foo", 4, new Object()); 
    } 

    @Benchmark 
    public void inlineStatic(Blackhole bh) { 
     inlineStaticVA(bh, "foo", 4, new Object()); 
    } 

    @Benchmark 
    public void loopNonStatic(Blackhole bh) { 
     loopNonStaticVA(bh, "foo", 4, new Object()); 
    } 

    @Benchmark 
    public void loopStatic(Blackhole bh) { 
     loopStaticVA(bh, "foo", 4, new Object()); 
    } 

    public void inlineNonStaticVA(Blackhole bh, Object... args) { 
     if (args.length > 0) bh.consume(args[0]); 
     if (args.length > 1) bh.consume(args[1]); 
     if (args.length > 2) bh.consume(args[2]); 
     if (args.length > 3) bh.consume(args[3]); 
    } 

    public static void inlineStaticVA(Blackhole bh, Object... args) { 
     if (args.length > 0) bh.consume(args[0]); 
     if (args.length > 1) bh.consume(args[1]); 
     if (args.length > 2) bh.consume(args[2]); 
     if (args.length > 3) bh.consume(args[3]); 
    } 

    public void loopNonStaticVA(Blackhole bh, Object... args) { 
     for (Object arg : args) { 
      bh.consume(arg); 
     } 
    } 

    public static void loopStaticVA(Blackhole bh, Object... args) { 
     for (Object arg : args) { 
      bh.consume(arg); 
     } 
    } 
} 

-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining पता चलता है कि सभी 4 वेरिएंट सफलतापूर्वक फोन करने वाले में inlined रहे हैं:

@ 28 bench.VarArgs::inlineNonStaticVA (52 bytes) inline (hot) 
    @ 27 bench.VarArgs::inlineStaticVA (52 bytes) inline (hot) 
    @ 28 bench.VarArgs::loopNonStaticVA (35 bytes) inline (hot) 
    @ 27 bench.VarArgs::loopStaticVA (33 bytes) inline (hot) 

परिणामों की पुष्टि बनाम गैर स्थिर तरीकों स्थिर बुला के बीच कोई प्रदर्शन अंतर नहीं है।

Benchmark    Mode Cnt Score Error Units 
VarArgs.inlineNonStatic avgt 20 9,606 ± 0,076 ns/op 
VarArgs.inlineStatic  avgt 20 9,604 ± 0,040 ns/op 
VarArgs.loopNonStatic avgt 20 14,188 ± 0,154 ns/op 
VarArgs.loopStatic  avgt 20 14,147 ± 0,059 ns/op 

हालांकि, जीसी प्रोफाइलर इंगित करता है कि vararg Object[] सरणी inline* तरीकों के लिए loop* तरीकों के लिए आवंटित किया जाता है, लेकिन नहीं।

Benchmark         Mode Cnt  Score  Error Units 
VarArgs.inlineNonStatic:·gc.alloc.rate.norm avgt 20 16,000 ± 0,001 B/op 
VarArgs.inlineStatic:·gc.alloc.rate.norm  avgt 20 16,000 ± 0,001 B/op 
VarArgs.loopNonStatic:·gc.alloc.rate.norm avgt 20 48,000 ± 0,001 B/op 
VarArgs.loopStatic:·gc.alloc.rate.norm  avgt 20 48,000 ± 0,001 B/op 

मुझे लगता है कि मूल बिंदु यह था कि स्थैतिक विधियां हमेशा मोनोमोर्फिक होती हैं। हालांकि, यदि विशेष कॉल साइट में बहुत से वास्तविक रिसीवर नहीं हैं तो JVM पॉलिमॉर्फिक तरीकों को भी रेखांकित कर सकता है।

+1

मैंने अभी प्रेजेंटेशन की जांच की है; किसी भी समय यह नहीं कहता है "क्योंकि यह एक स्थिर विधि है", वास्तव में, यह ओपी के प्रश्न के उदाहरण से पहले गैर-'स्थैतिक' तरीकों को रेखांकित करने की जेवीएम की क्षमता का भी वर्णन करता है। – Holger

+0

आह, यह मुझे होना चाहिए जो प्रस्तुति का गलत वर्णन करता है। – Fodder

+0

क्या आप कृपया ऑब्जेक्ट [] के आवंटन को समाप्त करके क्या मतलब समझ सकते हैं? क्या इसका मतलब है कि जेवीएम विधि हस्ताक्षर को 'लॉग (स्ट्रिंग, इंटेगर, ऑब्जेक्ट)' में बदलकर अनुकूलित करता है, क्योंकि यह जानता है कि क्या कहा जा रहा है? – Fodder

संबंधित मुद्दे