Có các hàm nội tuyến trong java không?


112

Có khái niệm về các hàm nội tuyến trong java hay nó được thay thế bằng một thứ gì khác không? Nếu có, nó được sử dụng như thế nào? Tôi đã nghe nói rằng public, staticfinalcác phương thức là các hàm nội tuyến. Chúng ta có thể tạo hàm nội tuyến của riêng mình không?


4
Chỉ để làm rõ, ý bạn là en.wikipedia.org/wiki/Inline_ Chức năng , không phải en.wikipedia.org/wiki/Anonymous_ Chức năng , phải không?
JW.

3
Như một nhận xét nhỏ, tối ưu hóa quá sớm là gốc rễ của mọi điều xấu. Nếu không hiểu đầy đủ về bản chất của công khai, tĩnh và cuối cùng, bạn không thể thực sự hiểu được tác động nội tuyến có thể có - và điều đó phụ thuộc vào JVM bạn đang sử dụng. Trước tiên, hãy chắc chắn trả lời lý do tại sao bạn cần nội tuyến điều gì đó: gần như chắc chắn rằng có những tối ưu hóa ROI cao hơn mà bạn có thể thực hiện ở những nơi khác.
Nathaniel Ford

Câu trả lời:


123

Trong Java, việc tối ưu hóa thường được thực hiện ở cấp độ JVM. Trong thời gian chạy, JVM thực hiện một số phân tích "phức tạp" để xác định phương pháp nào cần nội tuyến. Nó có thể tích cực trong nội tuyến và Hotspot JVM thực sự có thể nội tuyến các phương pháp không phải là cuối cùng.

Các trình biên dịch java hầu như không bao giờ nội dòng bất kỳ lệnh gọi phương thức nào (JVM thực hiện tất cả điều đó trong thời gian chạy). Họ biên dịch nội tuyến các hằng số thời gian (ví dụ: các giá trị nguyên thủy tĩnh cuối cùng). Nhưng không phải là phương pháp.

Để biết thêm tài nguyên:

  1. Bài báo: Công cụ hiệu suất Java HotSpot: Ví dụ về nội tuyến phương pháp

  2. Wiki: Nội tuyến trong OpenJDK , không được điền đầy đủ nhưng chứa các liên kết đến các cuộc thảo luận hữu ích.


15

Không, không có hàm nội tuyến trong java. Có, bạn có thể sử dụng một phương thức tĩnh công khai ở bất kỳ đâu trong mã khi được đặt trong một lớp công khai. Trình biên dịch java có thể mở rộng nội tuyến trên phương thức tĩnh hoặc phương thức cuối cùng, nhưng điều đó không được đảm bảo.

Thông thường, việc tối ưu hóa mã như vậy được thực hiện bởi trình biên dịch kết hợp với JVM / JIT / HotSpot cho các đoạn mã được sử dụng rất thường xuyên. Ngoài ra, các khái niệm tối ưu hóa khác như khai báo đăng ký các tham số không được biết đến trong java.

Không thể bắt buộc tối ưu hóa bằng cách khai báo trong java mà được thực hiện bởi trình biên dịch và JIT. Trong nhiều ngôn ngữ khác, những khai báo này thường chỉ là gợi ý của trình biên dịch (bạn có thể khai báo nhiều tham số thanh ghi hơn những gì bộ xử lý có, phần còn lại bị bỏ qua).

Khai báo các phương thức java static, final hoặc private cũng là những gợi ý cho trình biên dịch. Bạn nên sử dụng nó, nhưng không có bảo lãnh. Hiệu suất của Java là động, không tĩnh. Lần gọi đầu tiên đến hệ thống luôn chậm vì tải lớp. Các cuộc gọi tiếp theo nhanh hơn, nhưng tùy thuộc vào bộ nhớ và thời gian chạy, các cuộc gọi phổ biến nhất được tối ưu hóa phù hợp với hệ thống đang chạy, vì vậy máy chủ có thể trở nên nhanh hơn trong thời gian chạy!


3
finallàm cho không ảnh hưởng đến JIT nội tuyến
Steve Kuo

1
+1, Nhưng làm thế nào chúng tôi có thể kiểm tra xem phiên bản đã biên dịch của một phương thức có được nội tuyến hay không?
Pacerier

@Pacerier Nhưng tại sao chúng ta nên kiểm tra xem một cái gì đó có nội tuyến không?
Arne Burmeister

14

Java không cung cấp cách đề xuất thủ công rằng một phương thức nên được nội tuyến. Như @notnoop đã nói trong các nhận xét, nội tuyến thường được thực hiện bởi JVM tại thời điểm thực thi.


3
Hầu hết các trình biên dịch java không bao giờ gọi phương thức nội tuyến. Chủ yếu là JVM làm điều đó.
notnoop

Cảm ơn vì đã làm rõ điều đó. Tôi không chắc chính xác giai đoạn đó đã xảy ra. Tôi sẽ chỉnh sửa bài đăng của mình để phản ánh điều đó.
Thomas Owens

@ThomasOwens nó có, nhưng nó không công khaijdk.internal.vm.annotation.ForceInline
Eugene

4

Những gì bạn nói ở trên là chính xác. Đôi khi các phương thức cuối cùng được tạo dưới dạng nội tuyến, nhưng không có cách nào khác để tạo một cách rõ ràng một hàm nội tuyến trong java.


5
Các phương pháp cuối cùng không được đảm bảo là nội tuyến.
Thomas Owens

4
Trên HotSpot, việc thêm finalthậm chí không tạo ra bất kỳ sự khác biệt nào về việc phương thức có được nội tuyến hay không.
Tom Hawtin - tackline vào

4
@Thomas - đó là lý do tôi nói "phương pháp Đôi khi cuối cùng ..."
GreenieMeanie

@ TomHawtin-tackline bạn có nguồn có thẩm quyền cho việc đó không? Theo như tôi biết, các phương thức cuối cùng có thể được nội tuyến mà không cần sử dụng bộ bảo vệ kiểu, có nghĩa là công cụ sửa đổi làm cho phương thức nội tuyến hiệu quả hơn so với không có công cụ sửa đổi. Tôi biết rằng Jikes RVM đã tính đến điều này khi quyết định có nội tuyến hay không. Bạn có chắc chắn rằng HotSpot không làm điều gì đó tương tự?
Jannik Jochem

2

Ví dụ trong cuộc sống thực:

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

Sau đó, trong các lớp khác, tôi có thể thoát nếu mã đã hết hạn. Nếu tôi tham chiếu đến biến EXPIRED_ON từ một lớp khác, thì hằng số này nằm trong dòng mã byte, khiến rất khó để theo dõi tất cả các vị trí trong mã kiểm tra ngày hết hạn. Tuy nhiên, nếu các lớp khác gọi phương thức isExpired () thì phương thức thực sự được gọi, nghĩa là hacker có thể thay thế phương thức isExpired bằng một phương thức khác luôn trả về false.

Tôi đồng ý rằng sẽ rất tốt nếu buộc một trình biên dịch nội tuyến phương thức cuối cùng tĩnh cho tất cả các lớp tham chiếu đến nó. Trong trường hợp đó, bạn thậm chí không cần bao gồm lớp Điều khiển, vì nó sẽ không cần thiết trong thời gian chạy.

Từ nghiên cứu của tôi, điều này không thể được thực hiện. Có lẽ một số công cụ Obfuscator có thể làm điều này, hoặc bạn có thể sửa đổi quy trình xây dựng của mình để chỉnh sửa nguồn trước khi biên dịch.

Đối với việc chứng minh nếu phương thức từ lớp điều khiển được đặt nội tuyến đến lớp khác trong khi biên dịch, hãy thử chạy lớp khác mà không có lớp Điều khiển trong classpath.


2

Vâng, có những phương thức có thể được gọi là phương thức "nội tuyến" trong java, nhưng tùy thuộc vào jvm. Sau khi biên dịch, nếu mã máy của phương thức nhỏ hơn 35 byte, nó sẽ được chuyển sang phương thức nội tuyến ngay lập tức, nếu mã máy của phương thức nhỏ hơn 325 byte, nó có thể được chuyển thành phương thức nội tuyến, tùy thuộc vào jvm.


1
Đây là các giá trị mặc định cho máy ảo của Oracle, hãy xem docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

vì vậy, có vẻ như không có, nhưng bạn có thể sử dụng giải pháp thay thế này bằng cách sử dụng ổi hoặc triển khai lớp Hàm tương đương, vì lớp đó cực kỳ đơn giản, ví dụ:

    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);

vâng, đây là mã chết chỉ để minh họa cách tạo một khối mã phức tạp (bên trong {}) để thực hiện một điều gì đó quá cụ thể mà chúng tôi không nên làm phiền chúng tôi về việc tạo bất kỳ phương thức nào cho nó, AKA nội tuyến!


Có vẻ như một ý tưởng hợp lý. Bạn có phiên bản này không sử dụng các thư viện chung của google không?
ragerdl

0

Java9 có một trình biên dịch "Trước thời gian" thực hiện một số tối ưu hóa tại thời điểm biên dịch, thay vì thời gian chạy, có thể được coi là nội tuyến.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.