2010-10-13 37 views
31

Tôi đã cố gắng để hiểu những gì mà thực sự có nghĩa là:Phương pháp nội tuyến là gì?

inline chức năng

Trong C++, một hàm thành viên quy định tại khai báo lớp. (2) Một hàm gọi rằng trình biên dịch thay thế bằng mã thực tế cho hàm. Nội tuyến từ khóa có thể được sử dụng để gợi ý cho trình biên dịch để thực hiện nội tuyến mở rộng phần thân của thành viên hoặc chức năng không phải là thành viên.

inline

Để thay thế một lời gọi hàm với một bản sao mã của hàm trong biên dịch.

Ví dụ nó được viết một cái gì đó như:

Khi một phương pháp là cuối cùng, nó có thể là inlined.

đây: http://www.roseindia.net/javatutorials/final_methods.shtml

Bạn có thể cho tôi một ví dụ hay một cái gì đó hoặc về cơ bản giúp tôi hiểu những gì "nó có thể được inlined" nghĩa là gì.

Cảm ơn.

+1

Điều này sẽ giúp ích: http://java.sun.com/developer/onlineTraining/Programming/JDCBook/perf2.html#vm – codaddict

Trả lời

49

Nội tuyến là một tối ưu hóa được thực hiện bởi trình biên dịch Java Just-In-Time.

Nếu bạn có một phương pháp:

public int addPlusOne(int a, int b) { 
    return a + b + 1; 
} 

mà bạn gọi như thế này:

public void testAddPlusOne() { 
    int v1 = addPlusOne(2, 5); 
    int v2 = addPlusOne(7, 13); 

    // do something with v1, v2 
} 

trình biên dịch có thể quyết định thay thế cuộc gọi chức năng của bạn với các cơ quan chức năng, vì vậy kết quả sẽ có hiệu quả giống như sau:

public void testAddPlusOne() { 
    int v1 = 2 + 5 + 1; 
    int v2 = 7 + 13 + 1 

    // do something with v1, v2 
} 

Trình biên dịch thực hiện việc này để tiết kiệm chi phí o f thực sự thực hiện cuộc gọi hàm, điều này sẽ liên quan đến việc đẩy từng thông số vào ngăn xếp.

Điều này chỉ có thể được thực hiện rõ ràng cho các chức năng không phải ảo. Hãy xem xét điều gì sẽ xảy ra nếu phương thức được overriden trong một lớp con và kiểu đối tượng chứa phương thức không được biết cho đến khi chạy ... làm thế nào trình biên dịch biết mã nào cần sao chép: cơ sở phương thức của lớp cơ sở hoặc lớp con phương pháp cơ thể? Vì tất cả các phương thức là ảo theo mặc định trong Java, bạn có thể đánh dấu rõ ràng các phương thức không thể được ghi đè là final (hoặc đặt chúng vào lớp final). Điều này sẽ giúp trình biên dịch hiểu rằng phương thức đó sẽ không bao giờ được ghi đè lên, và nó an toàn để nội tuyến. (Lưu ý rằng trình biên dịch đôi khi có thể đưa ra quyết định này cho các phương pháp không phải là cuối cùng.)

Ngoài ra, hãy lưu ý từ có thể trong báo giá. Các phương thức cuối cùng không được đảm bảo là không thể in được. Có nhiều cách khác nhau mà bạn có thể đảm bảo một phương pháp không có khả năng được inlined, nhưng không có cách nào để buộc trình biên dịch vào nội tuyến. Nó sẽ hầu như luôn luôn biết tốt hơn bạn anyway khi nội tuyến sẽ giúp đỡ vs làm tổn thương tốc độ của mã kết quả.

Xem wikipedia để có tổng quan tốt về lợi ích và sự cố.

+10

Câu trả lời hay, nhưng như một lưu ý: Nếu bạn có một phương pháp không phải cuối cùng mà bạn * không * ghi đè, thì một JIT tốt có thể hình dung ra và in nó. Nếu bạn sau đó tải một lớp mà không ghi đè lên nó, nó có thể hoàn tác nội tuyến. – naiad

+0

Điểm tốt, tôi đã thêm nó vào phần trả lời. –

+0

Nó là rất giải thích, cảm ơn cho câu trả lời tuyệt vời này. – Tarik

9

Hãy nói rằng bạn có một lớp trông như thế này:

public class Demo { 
    public void method() { 
     // call printMessage 
     printMessage(); 
    } 

    public void printMessage() { 
     System.out.println("Hello World"); 
    } 
} 

Các cuộc gọi đến printMessage có thể được "inlined" theo cách sau:

public class Demo { 
    public void method() { 
     // call printMessage 
     System.out.println("Hello World"); // <-- inlined 
    } 

    public void printMessage() { 
     System.out.println("Hello World"); 
    } 
} 

(Điều này thực sự không thực hiện trên mức độ Java (thậm chí không ở cấp độ bytecode) nhưng trong quá trình biên dịch JIT, nhưng ví dụ trên minh họa khái niệm nội tuyến.)

Bây giờ hãy xem xét điều gì sẽ xảy ra nếu phương pháp printMessage được quá tải bởi một lớp, như thế này:

class SubDemo extends Demo { 
    public void printMessage() { 
     System.out.println("Something else"); 
    } 
} 

Bây giờ nếu trình biên dịch inlined cuộc gọi đến Demo.printMessage nó sẽ bị mắc kẹt với System.out.println("Hello World"); đó sẽ là sai trong trường hợp các đối tượng đã thực sự là một thể hiện của SubDemo.

Tuy nhiên, nếu phương pháp được khai báo là final, điều này sẽ không xảy ra trong bất kỳ trường hợp nào. Nếu phương thức là "cuối cùng", điều đó có nghĩa là nó không bao giờ có thể bị ghi đè với một định nghĩa mới, do đó, nó là an toàn để nội tuyến nó!

+0

Câu trả lời hay, nhưng như một ghi chú được sao chép từ câu trả lời khác: Nếu bạn có phương pháp không phải cuối cùng mà bạn không ghi đè, một JIT tốt có thể hình dung ra điều đó. Nếu bạn sau đó tải một lớp mà không ghi đè lên nó, nó có thể hoàn tác nội tuyến. – naiad

+0

Điều này rất lý giải, cảm ơn câu trả lời tuyệt vời này. – Tarik

10

Gọi hàm không phải là miễn phí. Máy phải duy trì một khung ngăn xếp để nó có thể trở lại phần gọi mã khi hàm được gọi hoàn tất. Việc duy trì ngăn xếp (bao gồm các tham số chức năng truyền trên ngăn xếp này) cần có thời gian.

Khi hàm nằm trong hàng, trình biên dịch sẽ thay thế cuộc gọi đến hàm bằng mã của hàm để người dùng có thể tránh được hình phạt về hiệu suất của cuộc gọi hàm tại thời gian chạy. Đây là một trong những thương mại cổ điển-off trong lập trình: mã thời gian chạy được một chút lớn hơn (chiếm nhiều bộ nhớ hơn), nhưng nó chạy nhanh hơn một chút.

+0

Cảm ơn. Ở đoạn đầu tiên, bạn thực sự đúng. – Tarik

Các vấn đề liên quan