มีฟังก์ชันอินไลน์ใน java หรือไม่?


112

มีแนวคิดของฟังก์ชันแบบอินไลน์ใน java หรือไม่หรือแทนที่อย่างอื่น? ถ้ามีใช้อย่างไร? ฉันได้ยินมาpublicแล้วstaticและfinalวิธีการเป็นฟังก์ชันแบบอินไลน์ เราสามารถสร้างฟังก์ชันอินไลน์ของเราเองได้หรือไม่?


4
เพื่อชี้แจงคุณหมายถึงen.wikipedia.org/wiki/Inline_functionไม่ใช่en.wikipedia.org/wiki/Anonymous_functionใช่ไหม
.

3
ในฐานะผู้แสดงความคิดเห็นเล็กน้อยการเพิ่มประสิทธิภาพก่อนเวลาอันควรเป็นรากเหง้าของความชั่วร้ายทั้งหมด หากไม่เข้าใจธรรมชาติของสาธารณะอย่างเต็มที่คงที่และขั้นสุดท้ายคุณจะไม่สามารถเข้าใจผลกระทบที่อาจเกิดขึ้นได้ - และขึ้นอยู่กับ JVM ที่คุณใช้ อย่าลืมตอบก่อนว่าทำไมคุณต้องอินไลน์บางอย่าง: เกือบจะแน่นอนว่ามีการเพิ่มประสิทธิภาพ ROI ที่สูงกว่าที่คุณสามารถทำได้จากที่อื่น
Nathaniel Ford

คำตอบ:


123

ใน Java การเพิ่มประสิทธิภาพมักจะทำที่ระดับ JVM ในขณะรันไทม์ JVM จะทำการวิเคราะห์ที่ "ซับซ้อน" บางอย่างเพื่อกำหนดวิธีการที่จะอินไลน์ มันสามารถก้าวร้าวในการอินไลน์และ Hotspot JVM สามารถอินไลน์วิธีการที่ไม่ใช่ขั้นสุดท้ายได้

คอมไพเลอร์ java แทบจะไม่อินไลน์การเรียกใช้เมธอดใด ๆ เลย (JVM ทำสิ่งนั้นทั้งหมดที่รันไทม์) พวกเขาทำค่าคงที่ในการคอมไพล์แบบอินไลน์ (เช่นค่าดั้งเดิมคงที่สุดท้าย) แต่ไม่ใช่วิธีการ

สำหรับแหล่งข้อมูลเพิ่มเติม:

  1. บทความ: Java HotSpot Performance Engine: Method Inlining Example

  2. Wiki: Inlining ใน OpenJDKไม่ได้รับการเติมเต็ม แต่มีลิงก์ไปยังการสนทนาที่เป็นประโยชน์


15

ไม่ไม่มีฟังก์ชัน inlineใน java ได้คุณสามารถใช้วิธีการคงที่สาธารณะที่ใดก็ได้ในรหัสเมื่อวางไว้ในคลาสสาธารณะ คอมไพเลอร์ java อาจทำการขยายแบบอินไลน์บนวิธีการแบบคงที่หรือขั้นสุดท้าย แต่ไม่รับประกัน

โดยทั่วไปแล้วการเพิ่มประสิทธิภาพโค้ดดังกล่าวจะกระทำโดยคอมไพเลอร์ร่วมกับ JVM / JIT / HotSpot สำหรับส่วนของโค้ดที่ใช้บ่อยมาก นอกจากนี้แนวคิดการเพิ่มประสิทธิภาพอื่น ๆ เช่นการประกาศการลงทะเบียนของพารามิเตอร์จะไม่เป็นที่รู้จักใน java

การเพิ่มประสิทธิภาพไม่สามารถบังคับโดยการประกาศใน java แต่ทำได้โดยคอมไพเลอร์และ JIT ในภาษาอื่น ๆ การประกาศเหล่านี้มักเป็นเพียงคำแนะนำของคอมไพเลอร์ (คุณสามารถประกาศพารามิเตอร์รีจิสเตอร์ได้มากกว่าที่โปรเซสเซอร์มีส่วนที่เหลือจะถูกละเว้น)

การประกาศเมธอด java แบบคงที่ขั้นสุดท้ายหรือไพรเวตยังเป็นคำแนะนำสำหรับคอมไพเลอร์ คุณควรใช้ แต่ไม่มีการรับประกัน ประสิทธิภาพของ Java เป็นแบบไดนามิกไม่ใช่แบบคงที่ การโทรเข้าระบบครั้งแรกมักจะช้าเนื่องจากการโหลดคลาส การโทรครั้งต่อไปจะเร็วกว่า แต่ขึ้นอยู่กับหน่วยความจำและรันไทม์การโทรที่พบบ่อยที่สุดจะได้รับการปรับให้เหมาะสมกับระบบที่กำลังทำงานอยู่ดังนั้นเซิร์ฟเวอร์อาจเร็วขึ้นในระหว่างรันไทม์!


3
finalไม่ส่งผลกระทบต่อ JIT inlining
Steve Kuo

1
+1 แต่เราจะทดสอบได้อย่างไรว่าเมธอดเวอร์ชันคอมไพล์นั้นอินไลน์หรือไม่?
Pacerier

@Pacerier แต่ทำไมเราต้องทดสอบว่ามีอะไรอยู่ในบรรทัด?
Arne Burmeister

14

Java ไม่มีวิธีแนะนำด้วยตนเองว่าควรใช้วิธีการแบบอินไลน์ ดังที่ @notnoop กล่าวไว้ในความคิดเห็นโดยทั่วไปแล้ว JVM จะทำอินไลน์ในเวลาดำเนินการ


3
คอมไพเลอร์ java ส่วนใหญ่ไม่เคยเรียกเมธอดแบบอินไลน์ ส่วนใหญ่ JVM ทำเช่นนั้น
notnoop

ขอบคุณที่ชี้แจง ฉันไม่แน่ใจว่าเกิดขึ้นในช่วงใดกันแน่ ฉันจะแก้ไขโพสต์ของฉันเพื่อให้สอดคล้องกับสิ่งนั้น
Thomas Owens

@ThomasOwens มันทำ แต่มันไม่ใช่สาธารณะjdk.internal.vm.annotation.ForceInline
Eugene

4

สิ่งที่คุณพูดข้างต้นถูกต้อง บางครั้งเมธอดสุดท้ายถูกสร้างเป็นแบบอินไลน์ แต่ไม่มีวิธีอื่นในการสร้างฟังก์ชันอินไลน์ใน java อย่างชัดเจน


5
วิธีสุดท้ายไม่รับประกันว่าจะเป็นแบบอินไลน์
Thomas Owens

4
ใน HotSpot การเพิ่มfinalไม่ได้สร้างความแตกต่างว่าเมธอดอยู่ในบรรทัดหรือไม่
Tom Hawtin - แท

4
@ โทมัส - นั่นคือเหตุผลที่ฉันพูดว่า "บางครั้งวิธีสุดท้าย ... "
GreenieMeanie

@ TomHawtin-tackline คุณมีแหล่งข้อมูลที่เชื่อถือได้หรือไม่? เท่าที่ฉันรู้วิธีสุดท้ายสามารถอินไลน์ได้โดยไม่ต้องใช้ตัวป้องกันประเภทซึ่งหมายความว่าตัวปรับเปลี่ยนทำให้การอินไลน์มีประสิทธิภาพมากกว่าการไม่มีตัวปรับแต่ง ฉันรู้ว่า Jikes RVM คำนึงถึงเรื่องนี้เมื่อตัดสินใจว่าจะอินไลน์หรือไม่ คุณแน่ใจหรือไม่ว่า HotSpot ไม่ได้ทำสิ่งที่คล้ายคลึงกัน?
Jannik Jochem

2

ตัวอย่างชีวิตจริง:

public class Control {
    public static final long EXPIRED_ON = 1386082988202l;
    public static final boolean isExpired() {
        return (System.currentTimeMillis() > EXPIRED_ON);
    }
}

จากนั้นในชั้นเรียนอื่นฉันสามารถออกได้หากรหัสหมดอายุ ถ้าฉันอ้างอิงตัวแปร EXPIRED_ON จากคลาสอื่นค่าคงที่จะอยู่ในบรรทัดของโค้ดไบต์ทำให้ยากมากที่จะติดตามตำแหน่งทั้งหมดในโค้ดที่ตรวจสอบวันหมดอายุ อย่างไรก็ตามหากคลาสอื่นเรียกใช้เมธอด isExpired () เมธอดจริงจะถูกเรียกซึ่งหมายความว่าแฮ็กเกอร์สามารถแทนที่เมธอด isExpired ด้วยวิธีอื่นซึ่งจะคืนค่าเป็นเท็จเสมอ

ฉันเห็นด้วยเป็นเรื่องดีมากที่จะบังคับให้คอมไพเลอร์อินไลน์วิธีสุดท้ายแบบคงที่ไปยังคลาสทั้งหมดที่อ้างถึง ในกรณีนี้คุณไม่จำเป็นต้องรวมคลาส Control ด้วยซ้ำเพราะไม่จำเป็นต้องใช้ในรันไทม์

จากการวิจัยของฉันสิ่งนี้ไม่สามารถทำได้ บางทีเครื่องมือ Obfuscator บางตัวสามารถทำได้หรือคุณอาจปรับเปลี่ยนกระบวนการสร้างของคุณเพื่อแก้ไขแหล่งที่มาก่อนที่จะคอมไพล์

สำหรับการพิสูจน์ว่าเมธอดจากคลาสควบคุมถูกวางแบบอินไลน์ไปยังคลาสอื่นระหว่างคอมไพล์หรือไม่ให้ลองรันคลาสอื่นโดยไม่มีคลาสคอนโทรลในคลาสพา ธ


2

มีวิธีที่เรียกว่าเมธอด "inline" ใน java ได้ แต่ขึ้นอยู่กับ jvm หลังจากคอมไพล์แล้วหากรหัสเครื่องของเมธอดน้อยกว่า 35 ไบต์โค้ดจะถูกโอนไปยังเมธอดแบบอินไลน์ทันทีหากโค้ดเครื่องของเมธอดมีขนาดน้อยกว่า 325 ไบต์ก็สามารถโอนไปยังเมธอดแบบอินไลน์ได้ขึ้นอยู่กับ jvm


1
ค่าเหล่านี้เป็นค่าเริ่มต้นสำหรับ VM ของ Oracle โปรดดูdocs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

ดูเหมือนว่าจะไม่มี แต่คุณสามารถใช้วิธีแก้ปัญหานี้โดยใช้ guava หรือการใช้งานคลาส Function ที่เทียบเท่าได้เนื่องจากคลาสนั้นง่ายมากเช่น:

    assert false : new com.google.common.base.Function<Void,String>(){
        @Override public String apply(Void input) {
            //your complex code go here
            return "weird message";
        }}.apply(null);

ใช่นี่เป็นรหัสตายเพียงเพื่อเป็นตัวอย่างวิธีสร้างบล็อกโค้ดที่ซับซ้อน (ภายใน {}) เพื่อทำบางสิ่งที่เฉพาะเจาะจงซึ่งไม่ควรรบกวนเราในการสร้างวิธีการใด ๆ สำหรับมัน AKA อินไลน์!


ดูเหมือนเป็นความคิดที่สมเหตุสมผล คุณมีเวอร์ชันที่ไม่ใช้ห้องสมุดทั่วไปของ Google หรือไม่?
ragerdl

0

Java9 มีคอมไพเลอร์ "Ahead of time" ที่ทำการเพิ่มประสิทธิภาพหลายอย่างในเวลาคอมไพล์แทนที่จะเป็นรันไทม์ซึ่งสามารถมองเห็นได้ว่าเป็นอินไลน์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.