Ảnh của Kelly Sikkema trên Unsplash
Mọi nhà tăng trưởng Java đều quen thuộc với vai trò của JVM trong hệ sinh thái của ngôn từ. Tuy nhiên, hầu hết đều không hiểu cách hoạt động giải trí của JVM. Mặc dù kiến thức đó không thiết yếu để trở thành một nhà tăng trưởng Java, nhưng việc hiểu rõ hơn về JVM sẽ giúp bạn viết mã tốt hơn vì khi đó, bạn sẽ biết mỗi dòng mã bạn viết tác động ảnh hưởng như thế nào đến quy trình đang diễn ra bên trong JVM .
Tuy nhiên, để hiểu cách hoạt động giải trí của JVM, bạn cần hiểu Java Bytecode là gì. Vì vậy, trong loạt bài viết này, tôi sẽ hướng dẫn bạn tìm hiểu và khám phá chi tiết cụ thể về mã byte Java và tầm quan trọng của nó so với JVM khi sau cuối bạn chạy chương trình của mình .
Java Bytecode là gì?
Nếu bạn đã nghe cách Java ca tụng về tính độc lập nền tảng của những chương trình Java tại một thời gian nào đó trong cuộc sống lập trình của bạn, bạn có Java bytecode để cảm ơn vì điều đó .
Java bytecode là tập lệnh mà JVM sử dụng để chạy chương trình của bạn. Vì bytecode được tạo cho chương trình của bạn độc lập với nền tảng mà nó đang chạy, miễn là bạn có JVM để giải thích bytecode, bạn có thể chạy chương trình của mình trên bất kỳ nền tảng nào mà không gặp sự cố.
Bytecode được tạo ra như thế nào?
Bytecode chỉ đơn giản là đầu ra bạn nhận được khi biên dịch một lớp Java. Các .class
tập tin bạn nhận được khi bạn biên dịch một lớp học thực sự là tập hợp các hướng dẫn bytecode mã của bạn chuyển thành. Nó cần một trình thông dịch như JVM để thông dịch và thực thi các hướng dẫn.
Bạn có thể xem mã bytecode của Java như thế nào?
Nếu bạn đã thử mở tệp. class, bạn phải biết rằng điều đó là không hề, trừ khi bạn đang sử dụng trình dịch ngược. Tuy nhiên, với một trình dịch ngược đang chơi, bạn không thực sự nhìn thấy bytecode mà là mã Java mà trình dịch ngược sẽ dịch lại bytecode thành .
Nếu bạn thực sự muốn xem mã bytecode, cách dễ nhất để làm như vậy là sử dụng dòng lệnh .
Bạn hoàn toàn có thể chạy lệnh sau để xem mã bytecode thực tiễn của tệp lớp .
javap -c -p -v [path to the .class file]
-c
được sử dụng để tháo rời lớp Java. Nếu bạn muốn xem mã bytecode thực tế, hãy sử dụng cờ này.-p
được sử dụng để hiển thị các thành viên riêng tư của lớp.-v
được sử dụng để xem thông tin dài dòng như kích thước ngăn xếp và nhóm hằng số.
Trước khi đi sâu vào Java bytecode, tất cả chúng ta phải hiểu một chút ít về cách JVM giải quyết và xử lý bytecode .
Các phương pháp là một trong những phần quan trọng nhất của mã Java cho JVM. Trên thực tiễn, thời hạn chạy của một chương trình Java là một tập hợp những phương pháp được gọi bởi JVM. Nó tạo ra một thứ gọi là khung cho mỗi phương pháp mà nó gọi ra và đặt khung đã tạo lên trên ngăn xếp của luồng hiện tại để thực thi .
Khung gồm có môi trường tự nhiên cục bộ được nhu yếu để duy trì quy trình thực thi của nó. Chủ yếu, nó chứa một mảng biến cục bộ và một ngăn xếp toán hạng. Hãy xem mỗi người trong số họ là gì .
Mảng biến cục bộ
Mảng biến cục bộ, như tên đã nói, được sử dụng để tàng trữ những biến cục bộ được sử dụng trong phương pháp. Ngoài ra, nó cũng tàng trữ những đối số được phương pháp đồng ý .
Trong mảng biến cục bộ được lập chỉ mục bằng 0, các chỉ mục đầu tiên được sử dụng để lưu trữ các đối số của phương thức. Sau khi chúng được lưu trữ, các biến cục bộ khác được lưu trữ trong mảng. Nếu phương thức là một phương thức thể hiện, thay vì phương thức tĩnh, chỉ mục thứ 0 được dành riêng để lưu trữ this
tham chiếu trỏ đến thể hiện đối tượng được sử dụng để gọi phương thức.
Hãy định nghĩa hai phương pháp : một phương pháp tĩnh và một phương pháp biểu lộ nhưng tương tự như về toàn bộ những cách khác .
Các mảng biến cục bộ của cả hai sẽ trông như thế này .
mảng biến cục bộ trong khung phương thức JVM
Toán hạng ngăn xếp
Ngăn xếp toán hạng là khoảng trống thao tác bên trong khung phương pháp. Vì nó là một ngăn xếp như tên cho thấy, bạn chỉ hoàn toàn có thể đẩy và bật những giá trị từ trên cùng của ngăn xếp toán hạng. Hầu hết những lệnh bytecode thuộc một giải pháp đơn cử hoặc tham gia vào việc đẩy những giá trị vào ngăn xếp hoặc bật những giá trị từ ngăn xếp để giải quyết và xử lý chúng .
Lệnh Bytecode load
và các phần mở rộng của nó được sử dụng để đẩy một giá trị được lưu trữ trong mảng biến vào ngăn xếp. Lệnh store
được sử dụng để bật các giá trị từ ngăn xếp và lưu trữ chúng trong mảng biến. Ngoài ra, có các hướng dẫn khác bật các giá trị từ ngăn xếp để xử lý chúng.
Ví dụ về các trường hợp như vậy là add
lệnh làm bật hai giá trị cao nhất từ ngăn xếp và thêm chúng lại với nhau và lệnh gọi phương thức bật giá trị cao nhất (số lượng phụ thuộc vào số lượng tham số được phương thức chấp nhận) từ ngăn xếp để chuyển chúng dưới dạng đối số cho phương thức. Nếu các lệnh này có giá trị kết quả, chúng sẽ được đẩy trở lại ngăn xếp.
aload_0 //push the reference to non-primitive data value at index 0 of the variable array
iload_2 //push the int value at index 4 of the variable array
iconst_3 //push the int 3 on to the stack
iadd //add the two top-most int values on the stack
istore_3 //pop the result of the add operation and store at index 6 of the variable array
How the operand stack and local variable array changes with the above instructions
Tôi đã viết một lớp Java đơn thuần để tất cả chúng ta hoàn toàn có thể thấy mã bytecode của nó .
Bây giờ, hãy chạy, hãy biên dịch lớp bằng javac
lệnh và xem mã bytecode bằng javap
lệnh. Không dài dòng, kết quả trông như thế này.
Khi bạn xem những hướng dẫn bytecode này, bạn sẽ xác lập được một số ít hướng dẫn quen thuộc, gồm có những lệnh load và const. Tuy nhiên, phần còn lại hoàn toàn có thể khiến bạn bồn chồn hơn một chút ít .
Giải mã bytecode
Nó không đáng sợ như vẻ ngoài của nó. Hãy cố gắng giải mã từng byte của SimpleClass. Hãy bắt đầu với phương pháp đơn giản nhất, isEven
.
private boolean isEven(int num) {
return num % 2 == 0;
}
private boolean isEven(int);
Code:
0: iload_1
1: iconst_2
2: irem
3: ifne 10
6: iconst_1
7: goto 11
10: iconst_0
11: ireturn
iconst_2
đẩy giá trị int 2 lên đầu ngăn xếp toán hạng.irem
lệnh được sử dụng để tìm phần dư từ phép chia giữa 2 số. Đó là lệnh đại diện cho logic của toán tử%. Nó bật 2 giá trị cao nhất trong ngăn xếp và đẩy kết quả trở lại ngăn xếp.- Lệnh ifne yêu cầu JVM di chuyển đến lệnh tại khoảng cách đã cho, trong trường hợp này là 10, nếu giá trị được lệnh xử lý không bằng 0. Lệnh bật phần tử trên cùng của ngăn xếp để thực hiện logic này. Nếu số được truyền là số chẵn, phần tử trên cùng sẽ là 0, trong trường hợp đó JVM được hướng dẫn chuyển đến lệnh ở chỉ số 6. Tuy nhiên, nếu giá trị ngăn xếp không phải là số 0, điều này xảy ra khi số không chẵn, JVM sẽ di chuyển hướng dẫn tại chỉ mục 10.
iconst_1
đẩy giá trị int 1 vào ngăn xếp. Điều này chỉ xảy ra nếu kết quảirem
là 1. Ở đây, 1 được sử dụng để biểu diễntrue
giá trị boolean .goto
hướng dẫn JVM đi tới lệnh được đưa ra trong phần bù, trong trường hợp này là 11.goto
lệnh được sử dụng để nhảy từ vị trí này trong bảng hướng dẫn sang vị trí khác.iconst_0
đẩy giá trị 0 vào ngăn xếp. Lệnh này được sử dụng khi điều kiện if hóa rafalse
. Giá trị 0 được truyền vào đóng vai trò là giá trị boolean false. Các hướng dẫn tại 3, 6, 7 xử lý trường hợp khi điều kiện if là đúng.ireturn
trả về giá trị int trên đầu ngăn xếp.
Mỗi số trước một lệnh chỉ ra chỉ số của byte khởi đầu của nó. Và mỗi mã bytecode được tạo bằng một opcode một byte, theo sau là không hoặc nhiều toán hạng .
Các mã lệnh là các lệnh như iload
, iconst
v.v. Tùy thuộc vào kích thước của các toán hạng, kích thước của mã byte có thể thay đổi từ một byte đến nhiều byte. Do đó, những khoảng trống mà bạn thấy trong các chỉ mục của bảng hướng dẫn. Ở đây, lệnh hai byte duy nhất là ifne
.
Trong bytecode của chúng tôi SimpleClass.class
tập tin, chúng ta có thể xem hướng dẫn khác thích invokespecial
, invokeinterface
và invokestatic
đó là hướng dẫn gọi phương pháp. Chúng ta sẽ nói về những điều đó trong phần tiếp theo của loạt bài viết này.
Trong thời gian chờ đợi, nếu bạn muốn hiểu ý nghĩa của từng hướng dẫn trong mã bytecode của mình, bạn có thể tham khảo bài viết tuyệt vời trên Wikipedia cung cấp danh sách hướng dẫn.
Phần kết luận
Tôi kỳ vọng bạn đã quản trị để khám phá nhiều về cách hoạt động giải trí của Java bytecode trong bài viết này. Trong những bài tiếp theo của loạt bài này, tất cả chúng ta sẽ đàm đạo về những hướng dẫn gọi phương pháp phức tạp hơn và cách JVM giải quyết và xử lý lệnh gọi phương pháp .
Với kiến thức rõ ràng hơn về Java bytecode và JVM, bạn sẽ hoàn toàn có thể viết mã tốt hơn. Bạn thậm chí còn hoàn toàn có thể thử nghiệm với việc tinh chỉnh và điều khiển bytecode chính nó trong thời hạn chạy của chương trình bằng cách sử dụng những thư viện như ASM. Nhưng như tôi đã nói, tất cả chúng ta sẽ nói thêm về chúng sau .
Source: kubet
Category: Tải Phầm Mềm
Leave a Reply