Trình biên dịch Java AOT hoạt động như thế nào?


18

Có một số công cụ hiện có ( Excelsior JET , v.v.) yêu cầu chuyển đổi ứng dụng Java thành các tệp thực thi gốc ( *.exe). Tuy nhiên, theo hiểu biết của tôi thì các công cụ này thực sự chỉ là tạo các trình bao bọc gốc gọi / thực thi javatừ trình bao hoặc dòng lệnh.

Nếu sự hiểu biết đó là không chính xác, tôi không thấy nó có thể như thế nào. Nếu một JVM ( javaprocess) đang chạy về cơ bản là một trình thông dịch hiệu năng cao, việc tải mã byte từ các tệp lớp Java một cách nhanh chóng, thì tôi không thấy một ứng dụng Java (một tập hợp các tệp mã byte đóng vai trò đầu vào cho JVM) có thể như thế nào thực sự chuyển đổi thành một thực thi.

Điều này là do quá trình JVM đã là một tệp thực thi riêng, lấy các tập tin của mã byte làm đầu vào. Để hợp nhất các tệp mã byte đó và quy trình JVM thành một tệp thực thi riêng thống nhất, dường như không thể thực hiện được mà không cần viết lại hoàn toàn JVM và khử lan can từ đặc tả JVM.

Vì vậy, tôi hỏi: làm thế nào để các công cụ này thực sự "biến đổi" các tệp lớp Java thành một tệp thực thi riêng, hoặc chúng?

Câu trả lời:


26

Tất cả các chương trình có một môi trường thời gian chạy. Chúng ta có xu hướng quên điều này, nhưng nó ở đó. Lib tiêu chuẩn cho C kết thúc các cuộc gọi hệ thống đến hệ điều hành. Objective-C có thời gian chạy kết thúc tất cả các thông điệp của nó đi qua.

Với Java, thời gian chạy là JVM. Hầu hết các triển khai Java mà mọi người quen thuộc đều giống với JVM của HotSpot, một trình thông dịch mã byte và trình biên dịch JIT.

Đây không phải là thực hiện duy nhất. Hoàn toàn không có gì nói rằng bạn không thể xây dựng thời gian chạy lib-esque tiêu chuẩn cho Java và biên dịch mã thành mã máy gốc và chạy trong thời gian chạy xử lý các cuộc gọi cho các đối tượng mới vào mallocs và truy cập tệp vào các cuộc gọi hệ thống trên máy. Và đó là những gì trình biên dịch Ahead Of Time (AOT chứ không phải JIT) làm. Gọi đó là thời gian chạy những gì bạn sẽ ... bạn có thể gọi nó là một thực hiện JVM (và nó không làm theo các đặc điểm kỹ thuật JVM) hoặc một môi trường runtime hoặc lib chuẩn cho Java. Nó ở đó và về cơ bản nó giống nhau.

Nó có thể được thực hiện bằng cách thực hiện lại javacđể nhắm mục tiêu vào máy gốc (đó là những gì mà GCJ đã làm). Hoặc có thể được thực hiện bằng cách dịch mã byte được tạo bởi mã javacmáy (hoặc byte) cho máy khác - đó là những gì Android làm. Dựa trên Wikipedia , đó là điều mà Excelsior JET cũng làm ("Trình biên dịch biến mã byte Java di động thành các tệp thực thi được tối ưu hóa cho phần cứng và hệ điều hành (HĐH) mong muốn") và điều tương tự cũng đúng với RoboVM .

Có các biến chứng bổ sung với Java có nghĩa là điều này rất khó thực hiện như một cách tiếp cận độc quyền. Tải động các lớp ( class.forName()) hoặc các đối tượng được ủy quyền yêu cầu các động lực mà trình biên dịch AOT không dễ dàng cung cấp và do đó các JVM tương ứng của chúng cũng phải bao gồm trình biên dịch JIT (Excelsior JET) hoặc trình thông dịch (GCJ) để xử lý các lớp không thể được biên dịch trước tự nhiên.

Hãy nhớ rằng, JVM là một đặc tả , với nhiều triển khai . Thư viện chuẩn C cũng là một đặc điểm kỹ thuật với nhiều triển khai khác nhau.

Với Java8, một chút công việc đã được thực hiện trong quá trình biên dịch AOT. Tốt nhất, người ta chỉ có thể tóm tắt AOT nói chung trong giới hạn của hộp văn bản. Tuy nhiên, trong Hội nghị thượng đỉnh ngôn ngữ JVM năm 2015 (tháng 8 năm 2015), đã có một bài thuyết trình: Java Goes AOT (video youtube). Video này dài 40 phút và đi sâu vào nhiều khía cạnh kỹ thuật và điểm chuẩn hiệu suất sâu hơn.


Xin lỗi, tôi không biết nhiều về điều này, nhưng điều này có nghĩa là java bây giờ có nguồn gốc không? Hoặc điều đó có nghĩa là có một cờ trình biên dịch mới cho phép chúng ta biên dịch các chương trình java thành mã gốc nếu chúng ta muốn và chúng ta vẫn có tùy chọn để biên dịch thành mã byte?
Pavel

@ paulpaul1076 Tôi khuyên bạn nên xem video mà tôi đã liên kết. Có khá nhiều trong đó hơn là tôi có thể phù hợp với một bình luận.

4

gcj ví dụ tối thiểu

Bạn cũng có thể quan sát một triển khai nguồn mở như thế nào gcj(hiện đã lỗi thời). Ví dụ: tệp Java:

public class Main {
    public static void main(String args[]) {
        System.out.println("hello world");
    }
}

Sau đó biên dịch và chạy với:

gcj -c Main.java
gcj --main=Main -o Main Main.o
./Main

Bây giờ bạn có thể tự do dịch ngược nó và xem nó hoạt động như thế nào.

file Main.o nói rằng đó là một tập tin elf.

readelf -d Main | grep NEEDED nói rằng nó phụ thuộc vào các thư viện động:

0x0000000000000001 (NEEDED)             Shared library: [libgcj.so.14]
0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

Vì vậy libgcj.so phải là nơi thực hiện chức năng Java.

Sau đó, bạn có thể dịch ngược nó với:

objdump -Cdr Main.o

và xem chính xác cách nó được thực hiện.

Trông giống như C ++, rất nhiều tên gọi xáo trộn và gọi hàm đa hình gián tiếp.

Tôi tự hỏi như thế nào đá thu gom rác thải trong Nó sẽ là giá trị xem xét:. Https://stackoverflow.com/questions/7100776/garbage-collection-implementation-in-compiled-languages và ngôn ngữ biên dịch khác với GC như Go.

Đã thử nghiệm trên Ubuntu 14.04, GCC 4.8.4.

Ngoài ra, hãy xem https://en.wikipedia.org/wiki/Android_R.78 , xương sống của Android 5 trở đi, có AOT đầy đủ để tối ưu hóa các ứng dụng Android.

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.