2011-01-30 3 views
15

Trong Java, "mã nhị phân" có nghĩa là "mã bytecode Java không?"Java - Mã nhị phân có giống với ByteCode không?

Đây có phải là luồng trong Java không?

Java Tệp (java) -> [javac] -> bytecode Tệp (.class) -> [JVM/Java Interpreter] -> Chạy nó (bằng cách đầu tiên chuyển đổi nó thành mã nhị phân cụ thể với máy)

Cảm ơn!

+5

Trong ngữ cảnh nào bạn thấy thuật ngữ "mã nhị phân?" – templatetypedef

+0

Tôi đọc đâu đó mã java đầu tiên được chuyển thành bytecode độc ​​lập của máy, trong khi một số đã nói, nó được chuyển thành mã nhị phân. Vì vậy, tôi hơi bối rối. –

+3

** Mọi thứ ** là "mã nhị phân" !!! Ôi không!! –

Trả lời

21

Câu trả lời tùy thuộc vào ý của bạn là binary code.

Java bytecode là một định dạng dữ liệu nhị phân đó bao gồm việc tải thông tin và thực hiện hướng dẫn cho máy ảo Java. Theo nghĩa đó, Java bytecode là loại đặc biệt gồm mã nhị phân.

Khi bạn sử dụng thuật ngữ "mã nhị phân" để có nghĩa là hướng dẫn máy cho kiến ​​trúc bộ xử lý thực (như IA-32 hoặc Sparc) thì khác.
Java bytecode không phải là mã nhị phân theo nghĩa đó. Nó không phải là bộ xử lý cụ thể.

7

Không có thứ như "bytecode độc ​​lập với máy" (nó sẽ không có ý nghĩa gì nếu bạn nghĩ về nó). Bytecode chỉ là (cho các mục đích của câu trả lời này) được sử dụng cho những thứ như máy ảo. Các máy ảo (chẳng hạn như JVM) INTERPRET bytecode và sử dụng một số biên dịch đơn giản và phức tạp trong thời gian ngắn (mà IS phụ thuộc vào máy/nền tảng) để cung cấp cho bạn sản phẩm cuối cùng.

Do đó, cả hai câu trả lời đều đúng và sai. Trình biên dịch Java biên dịch mã thành mã Java bytecode (không độc lập với máy). Các tập tin *.class bytecode được đặt ở dạng nhị phân - chúng có thể thực thi được. Máy ảo sau đó diễn giải các tệp nhị phân *.class này (lưu ý: khi mô tả tệp dưới dạng nhị phân, phần nào đó là từ nhầm) và thực hiện nhiều công cụ tuyệt vời khác. Thường xuyên hơn không, JVM sử dụng một cái gì đó gọi là JIT (biên dịch chỉ trong thời gian), tạo ra các hướng dẫn cụ thể cho từng nền tảng hoặc máy cụ thể để tăng tốc các phần thực thi khác nhau. JIT là một chủ đề khác cho một ngày khác, tuy nhiên.

Sửa:

Java File (.java) -> [javac.exe] -> ByteCode File (.class) -> [JVM/Java Interpreter] -> Running it(by first converting it into binary code specific to the machine) 

này là không chính xác. JVM không "chuyển đổi" bất cứ thứ gì. Nó chỉ đơn giản là giải thích bytecode. Phần duy nhất của JVM mà "chuyển đổi" bytecode là khi trình biên dịch JIT được gọi, đây là một trường hợp đặc biệt và không nên được khái quát hóa.

+0

Bạn vừa nói, "biên dịch JIT" là máy độc lập. Nhưng tôi đã đọc rằng JVM là cụ thể cho mỗi máy, không giống như một ByteCode. –

+0

Biên dịch JIT là một phần nhỏ của cách JVM hoạt động (và phần CHỈ là "viết lại" mã cho một máy/nền tảng cụ thể). VM là một trình thông dịch cụ thể cho nền tảng/máy, nhưng bytecode là NOT. –

+1

Titerenco: Có lẽ tôi đã không nhận được "biên dịch ngay lập tức (mà máy IS/nền tảng độc lập)", nhưng biên dịch JIT phụ thuộc vào nền tảng, bắt đầu từ giai đoạn LIR trong luồng nó tạo mã phụ thuộc nền tảng! Kết quả của việc biên dịch là mã máy phụ thuộc nền tảng gốc, vì vậy nó không thể độc lập ... bytecode là nền tảng của nền tảng độc lập ... – Maxym

4

Cả C/C++ (để lấy làm ví dụ) và các chương trình Java được biên dịch thành Mã nhị phân.Thuật ngữ chung này chỉ có nghĩa là tệp mới được tạo không mã hóa các hướng dẫn theo cách có thể đọc được. (nghĩa là bạn sẽ không thể mở tệp được biên dịch trong một chương trình văn bản và đọc nó).

Mặt khác, mã hóa nhị phân 0 và 1 (hoặc đại diện), phụ thuộc vào trình biên dịch tạo ra. Trong trường hợp của Java, nó tạo ra các hướng dẫn được gọi là Bytecode, được giải thích bởi JVM. Trong các trường hợp khác, đối với các ngôn ngữ khác, nó có thể tạo ra các lệnh IA-32 hoặc SPARC.

Tóm lại, cách các điều khoản Mã nhị phânJava bytecode đang trái ngược với nhau là sai lầm. Lý do là tạo ra sự khác biệt giữa mã nhị phân thông thường phụ thuộc vào máy và mã byte bytecode (cũng là mã nhị phân) mà không phải là.

11

JVM là một chương trình rất phức tạp và dòng chảy ở một mức độ không thể đoán trước. Ví dụ. dòng chảy bên trong HotSpot JVM là một cái gì đó như sau:

1) phải mất bytecode của bạn và giải thích nó
2) nếu một số phương pháp được thực hiện khá thường xuyên (một số lượng lần trong một số khoảng thời gian) nó được đánh dấu như là một " phương thức "hot" và JVM lập lịch trình biên dịch của nó cho nền tảng mã máy phụ thuộc (đó là những gì bạn đã gọi là mã nhị phân?). Luồng đó trông giống như sau:

ByteCode 
--> Hige-level Intermediate Representation (HIR) 
    --> Middle-level Intermediate Representation (MIR) 
    --> Low-level Intermediate Representation (LIR) 
     --> Register Allocation 
     --> EMIT (platform dependent machine code) 

Mỗi bước trong luồng đó là quan trọng và giúp JVM thực hiện một số tối ưu hóa mã của bạn. Nó không thay đổi thuật toán của bạn tất nhiên, tối ưu hóa chỉ có nghĩa là một số chuỗi mã có thể được phát hiện và trao đổi với mã thực hiện tốt hơn (sản xuất cùng một kết quả). Bắt đầu từ giai đoạn LIR, mã sẽ trở thành nền tảng phụ thuộc (!).

Bytecode có thể tốt cho việc giải thích, nhưng không đủ tốt để dễ dàng chuyển đổi thành mã gốc của máy. HIR chăm sóc nó và mục đích của nó là nhanh chóng chuyển đổi bytecode thành một biểu diễn trung gian. MIR biến tất cả các hoạt động thành hoạt động ba toán hạng; Bytecode được dựa trên stack hoạt động:

iload_0 
iload_1 
iand 

đó là bytecode cho thao tác đơn giản and, và đại diện cấp trung cho điều này sẽ loại các nội dung sau:

and v0 v1 -> v2 

LIR phụ thuộc vào nền tảng, có tính đến ví dụ đơn giản của chúng tôi với and hoạt động, và xác định nền tảng của chúng tôi như x86, sau đó đoạn mã của chúng tôi sẽ là:

x86_and v1 v0 -> v1 
x86_move v1 -> v2 

vìHoạt độngmất hai toán hạng, đầu tiên là đích, một số khác là nguồn, và sau đó chúng ta đặt giá trị kết quả cho một biến "" khác. Giai đoạn tiếp theo là "đăng ký phân bổ", bởi vì nền tảng x86 (và có lẽ hầu hết những người khác) làm việc với các thanh ghi, chứ không phải các biến (như biểu diễn trung gian), cũng như ngăn xếp (như bytecode). Đoạn mã của chúng tôi phải giống như sau:

x86_and eax ecx -> eax 

và tại đây bạn có thể nhận thấy sự vắng mặt của thao tác "di chuyển". Mã của chúng tôi chỉ chứa một dòng và JVM đã tìm ra rằng việc tạo một biến ảo mới không cần thiết; chúng tôi chỉ có thể sử dụng lại đăng ký eax. Nếu mã đủ lớn, có nhiều biến và làm việc với chúng một cách chuyên sâu (ví dụ:sử dụng eax ở đâu đó bên dưới, vì vậy chúng tôi không thể thay đổi giá trị của nó), sau đó bạn sẽ thấy thao tác di chuyển còn lại trong mã máy. Đó là một lần nữa về tối ưu hóa :)

Đó là dòng JIT, nhưng tùy thuộc vào việc triển khai VM có thể thêm một bước nữa - nếu mã được biên dịch (là "nóng") và vẫn được thực hiện nhiều lần, JVM lên lịch tối ưu hóa mã (ví dụ: sử dụng nội tuyến).

Vâng, kết luận là đường dẫn từ bytecode đến mã máy khá thú vị, một chút không lường trước được và phụ thuộc vào nhiều thứ.

btw, quy trình trên được gọi là "Giải thích chế độ hỗn hợp" (khi JVM đầu tiên giải mã bytecode, và sau đó sử dụng biên dịch JIT), ví dụ về JVM đó là HotSpot. Một số JVM (như JRockit từ Oracle) chỉ sử dụng trình biên dịch JIT.

Đây là một mô tả rất đơn giản về những gì đang diễn ra ở đó. Tôi hy vọng rằng nó sẽ giúp hiểu được dòng chảy bên trong JVM ở mức rất cao, cũng như nhắm vào câu hỏi về sự khác biệt giữa mã byte và mã byte. Để tham khảo và các vấn đề khác không được đề cập ở đây và liên quan đến chủ đề đó, vui lòng đọc chủ đề tương tự "Why are compiled Java class files smaller than C compiled files?".

Cũng cảm thấy tự do để phê phán câu trả lời này, chỉ cho tôi đến sai lầm hoặc hiểu lầm của tôi, tôi luôn sẵn sàng để nâng cao kiến ​​thức của tôi về JVM :)

+0

@magnetar: cảm ơn bạn, vui mừng vì nó không lãng phí thời gian;) – Maxym

1

trả lời tôi thấy ngày hôm nay cho câu hỏi trên:

Nguồn: JLS

Đang tải đề cập đến quá trình tìm biểu mẫu nhị phân của một lớp hoặc loại giao diện với tên cụ thể, có thể bằng cách tính toán nó một cách nhanh chóng, nhưng thường hơn bằng cách truy xuất biểu diễn nhị phân trước đó được tính từ mã nguồn một trình biên dịch Java và xây dựng từ binar đó y form, một đối tượng Class để biểu diễn lớp hoặc giao diện.

Ngữ nghĩa chính xác của tải được đưa ra trong Chương 5 của Đặc tả máy ảo Java, Java SE 7 Edition. Ở đây chúng tôi trình bày tổng quan về quá trình từ quan điểm của ngôn ngữ lập trình Java.

Định dạng nhị phân của lớp hoặc giao diện thường là định dạng tệp lớp được mô tả trong Đặc tả máy ảo Java, Java SE 7 được trích dẫn ở trên, nhưng các định dạng khác là có thể, miễn là chúng đáp ứng các yêu cầu được chỉ định trong §13.1 . Phương thức defineClass của lớp ClassLoader có thể được sử dụng để xây dựng các đối tượng Class từ các biểu diễn nhị phân trong định dạng tệp lớp.