2011-08-16 36 views
7

A working document mô tả trạng thái Project Lambda đề cập đến cái gọi là kiểu SAM (phương pháp trừu tượng đơn lẻ). Theo như tôi biết, đề xuất lambda hiện tại không ảnh hưởng đến thời gian chạy chỉ là trình biên dịch bằng cách thực hiện chuyển đổi tự động có thể từ các biểu thức lambda thành các kiểu này.Java - tối ưu hóa loại SAM

Tôi nghĩ trong trường hợp lý tưởng, các trường hợp của các loại SAM có thể được biểu diễn nội bộ bằng con trỏ hàm. Do đó JVM có thể tránh việc cấp phát bộ nhớ cho những trường hợp này.

Tôi tự hỏi liệu các máy ảo hiện đại có thể cung cấp tối ưu hóa như vậy hay không.

+0

Khi bạn nói "con trỏ hàm", bạn có nghĩa là con trỏ đơn giản để bắt đầu mã chức năng không? – ffriend

+0

@ffriend - Vâng, tôi có.Tôi biết có một số vấn đề với cách tiếp cận này, ví dụ nó có thể đồng bộ hóa trên một đối tượng. Nhưng JVM cũng có thể thực hiện một số tối ưu hóa không tầm thường khác, ví dụ như phác thảo các phương thức ảo. –

Trả lời

6

@ Tamás Bạn có lẽ nên có một chi của này mailing list bài bởi Brian Goetz:

http://mail.openjdk.java.net/pipermail/lambda-dev/2011-August/003877.html

Về cơ bản, trừu tượng lambda hiện đang triển khai sử dụng các đối tượng. Tuy nhiên, nó đã được thiết kế để cho phép thực hiện thay thế lambdas, mà sẽ là "nhỏ hơn" so với trường hợp của các lớp học.

Bạn có thể nghĩ về tình huống tương tự như autoboxing - ints được đóng hộp thành Số nguyên, nhưng có biểu diễn "nhỏ hơn" (dưới dạng int).

Hiện tại, lambdas phải được đóng hộp cho các trường hợp của các loại SAM, b/c JVM hiện không có cách nào đại diện cho một lambda với bất kỳ cấu trúc nhỏ hơn nào. Trong tương lai, có thể có một tiêu chuẩn JVM mới bao gồm "các hàm nguyên thủy" có thể đại diện cho lambdas như một cái gì đó khác với các đối tượng. Vì vậy, để trả lời câu hỏi của bạn, loại tối ưu bạn đề xuất ở trên, có thể là có thể, nhưng nó có thể đi kèm với công việc sau Java 8 trên "các chức năng nguyên thủy" thay vì là một tính năng cụ thể cho việc triển khai thực hiện.

5

Không có gì khó khăn trong việc chuyển đổi các lớp phương thức đơn thành con trỏ hàm, nhưng bạn thiếu một điều: biểu thức lambda không chỉ là hàm, chúng là đóng. Sự khác biệt là đóng cửa có thể nắm bắt các biến bên ngoài. Xem xét ví dụ tiếp theo trong giả Java:

public Adder makeAdder(double startNumber) { 
    return #{ int number -> number + startNumber} 
} 

... 

int startNumber = 5; 
Adder add5 = makeAdder(startNumber); 
add5.invoke(4); // ==> 9 

Trong ví dụ này hàm lambda, được gọi bởi makeAdder(), là biến được xác định bên ngoài lambda này. Đó là lý do tại sao nó được gọi là "đóng cửa" - chúng được "đóng cửa" các biến miễn phí của chúng (trong trường hợp này - trên startNumber). Để xử lý các trường hợp đóng cửa như vậy phải giữ cả hai con trỏ đến một hàm và con trỏ đến môi trường của nó. Vì vậy, bạn nhận được một số cấu trúc dữ liệu có một phương thức và ít nhất một biến. Nhưng nó không phải là một định nghĩa của một đối tượng trong OOP? Vì vậy, lý do để tạo ra các loại đối tượng mới là gì nếu bạn có thể biến nó thành một thể hiện của lớp ẩn danh?

Tuy nhiên, một số tối ưu hóa khác về các lớp ẩn danh như vậy có thể được thực hiện. Tài liệu làm việc mà bạn đã đề cập đến đề cập đến một số trong số đó, ví dụ, suy ra và sử dụng các biến cuối cùng hiệu quả (mặc dù điều này được thực hiện chủ yếu để cho phép lambdas trên JVM trong chính, không tối ưu hóa mã). Lớp ẩn danh được sản xuất cũng có thể được thực hiện cuối cùng và hầu hết các JVM đã có tối ưu hóa tốt cho các loại và lớp cuối cùng.

Các cải tiến khác cũng có thể liên quan đến tham chiếu đến môi trường - có rất nhiều tùy chọn ở đó.

+0

Cảm ơn bạn đã trả lời! Điều duy nhất tôi lo lắng là cấp phát bộ nhớ cho các đối tượng này, điều này có thể hạn chế đồng thời, vì theo tôi biết mọi phân bổ bộ nhớ liên quan đến một số đồng bộ hóa. Tất nhiên tôi biết rằng quản lý các đối tượng tái sử dụng là trách nhiệm của lập trình viên, tôi chỉ muốn biết liệu JVM có thể tránh việc cấp phát bộ nhớ cho các đối tượng này hay không. –

+1

@ Tamás: bạn có thể chỉ ra các tài nguyên về đồng bộ hóa trong khi cấp phát bộ nhớ không? Tôi không thể tìm thấy bất kỳ thông tin nào về chủ đề này, nhưng tôi tin rằng việc cấp phát bộ nhớ mặc định trong JVM không sử dụng những thứ như 'sync': phân bổ một luồng trong các máy ảo hiện đại chỉ yêu cầu một chỉ định cho tham chiếu và tăng một con trỏ. Tôi tin rằng chủ đề an toàn trong phân bổ bộ nhớ đa luồng được thực hiện bởi một số cấu trúc rất thấp, có thể dựa trên hoạt động nguyên tử của bộ vi xử lý, và do đó cũng rất nhanh. Nếu điều này là như vậy, không có vấn đề gì phải lo lắng về việc đồng bộ hóa trong quá trình tạo kết nối. – ffriend

+3

@ Tamás Hotspot sử dụng bộ đệm TLS (lưu trữ cục bộ) trong nội bộ và chỉ khi được phân bổ đầy đủ trên heap toàn cầu, có thể phải chịu phí đồng bộ hóa, nhưng lại không tốn kém - chỉ là tăng dần con trỏ sau tất cả trong trường hợp bình thường (Tôi không biết nhưng gần như chắc chắn được thực hiện với một vòng lặp CAS). – Voo