You are on page 1of 32

ĐẠI HỌC QUỐC GIA HÀ NÔI - ĐAI HỌC CÔNG NGHỆ

KHOA CÔNG NGHỆ THÔNG TIN


----------------------*----------------------

XEMINA: LẬP TRÌNH NHÚNG

JAVA VIRTUAL MACHINE


(Máy Ảo Java).

Giáo viên hướng dẫn: Th


S.Vũ Quang Dũng
Nhóm thực hiện: Nhóm 12, lớp K49CNPM
Trương Đình Trường
Vũ Thị Lý
Phạm Văn Tùng
Nguyễn Phương Thảo

HÀ NỘI 2007
MỤC LỤC
MỤC LỤC.............................................................................................................................ii
JAVA VIRTUAL MACHINE................................................................................................1
(Máy Ảo Java).......................................................................................................................1
12.1 Thế nào là máy ảo Java............................................................ ...................1
12.1.1 Thời gian sống của máy ảo Java............................................. .................1
12.2 Kiến trúc trong máy ảo java............................................... ........................2
12.2.1 Các kiểu dữ liệu............................................................ ............................5
12.2.2 Kích thước của từ......................................................... ............................6
12.2.3 Class Loader subsystem............................................... ............................7
12.2.4 Vùng phương thức (Method area).............................................. .............9
12.2.5 Bộ nhớ Heap.............................................................................. ..............11
12.2.6 Garbage Collection............................................................. ....................12
12.2.7 Ngăn xếp Java...................................................................... ...................18
12.2.7.1 Stack frame................................................................................................................................19
12.2.7.2 Ngăn xếp toán hạng...................................................................................................................21
12.2.7.3 Frame data.................................................................................................................................21
12.2.7.4 Ngăn xếp phương thức cơ sở....................................................................................................25

12.2.8 Máy thực thi ............................................................................ ...............26


12.2.8.1 Tập chỉ lệnh...............................................................................................................................26
12.2.8.2 Kĩ thuật thực thi ........................................................................................................................27
TÀI LIỆU THAM KHẢO...................................................................................................30
JAVA VIRTUAL MACHINE

(Máy Ảo Java)

12.1 Thế nào là máy ảo Java.


Để nói về máy ảo Java thì phải làm rõ 3 vấn đề:
− Đặc tả trừu tượng

− Một sự cài đặt cụ thể

− Một thể hiện của cài đặt

Đặc tả trừu tượng nói rõ những thành phần, chức năng mà một máy ảo Java
cần có. Một cài đặt là dựa trên các đặc tả trừu tượng đó thì các hãng khác nhau tạo
ra các cài đặt khác nhau cho máy ảo Java . Còn một thể hiện chỉ có khi một ứng
dụng Java chạy.
Một ứng dụng Java chạy bên trong một thể hiện của một cài đặt cụ thể của một
đặc tả trừu tượng của máy ảo Java. Thuật ngữ JVM trong tài liệu này dùng để chỉ cả
3 ý nghĩa này.

12.1.1 Thời gian sống của máy ảo Java.


Nhiệm vụ của một thể hiện thời gian chạy là rất cụ thể: đó là chạy ứng dụng
Java. Khi một ứng dụng Java bắt đầu thì một nó được sinh ra. Khi ứng dụng hoàn
thành thì nó chết.Khi bạn chạy 3 ứng dụng đồng thời, trên cùng một máy tính, sử
dụng cùng sự thực thi thì bạn vẫn nhận được 3 cài đặt của JVM. Mỗi ứng dụng sẽ
chạy bên trong cài đặt JVM của nó.
Một cài đặt JVM bắt đầu chạy ứng dụng độc lập của nó bằng cách gọi hàm
main() của một vài lớp khởi tạo. Xem xét một ví dụ sau:
Class echo{
Public static void main(String args[])
{
System.out.println(“Hello world”);
}
Java Virtual Machine 2

}
Hàm main() trong lớp khởi tạo có vai trò như là điểm bắt đầu của luồng khởi
tạo ứng dụng. Luồng khởi tạo ứng dụng có thể sinh ra hoặc kết thúc những luồng
khác.
Trong JVM thì các luồng được phân chia thành 2 loại là daemon( hậu cảnh) và
non-daemon. Một tiến trình daemon là một luồng thông thường được sử dụng bởi
chính máy ảo JVM như luồng thực thi dọn dẹp bộ nhớ. Ứng dụng có thể đánh dấu
bất kì luồng nào mà nó tạo ra là luồng daemon. Luồng khởi đầu của ứng dụng là
luồng non-daemon.
Một ứng dụng java tiếp tục thực thi( một cài đặt của máy ảo java vẫn tiếp tục
tồn tại) khi mà bất kì một luồng non-daemon nào vẫn chạy.
Khi mà tất cả các luồng non-daemon của ứng dụng Java kết thúc thì cài đặt
của máy ảo Java sẽ kết thúc theo. Chương trình cũng sẽ kết thúc nếu nó gọi hàm
exit() của lớp Runtime hoặc lớp System.

12.2 Kiến trúc trong máy ảo java.


Trong đặc tả của máy ảo java thì hành vi của một máy ảo Java được mô tả
trong phạm vi của các hệ con : vùng bộ nhớ, kiểu dữ liệu, và các chỉ thị. Các thành
phần này môt tả kiếm trúc trừu tượng bên trong của một máy ảo java trừu tượng.
Đặc tả định nghĩa những hành vi được yêu cầu của bất cài đặt thi máy ảo java nào.
Hình 12-1 thể hiện một sơ đồ khối của máy ảo java bao gồm các hệ thống con
và vùng bộ nhớ được mô tả trong đặc tả. Trong các chương trước ta đã biết là trong
một máy ảo java thì có một class loader subsystem, nó là một cơ chế cho việc tải
các kiểu ( các lớp và giao diện) được cho bởi tên. Mỗi JVM còn có một bộ thực thi
Execute engine là một cơ chế chịu trách nhiệm thực thi những chỉ thị được chứa
trong các phương thức của các lớp được tải.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 3

Hình12-1: Kiến trúc bên trong của máy ảo java.


Khi một máy ảo java chạy một chương trình nó cần bộ nhớ để chứa các đối
tượng của nó bao gồm mã bytecodes và các thông tin khác mà nó trích rút được từ
các file lớp được tải, các đối tượng, các tham số của hàm, các giá trị trả lại, biến cục
bộ, kết quả tính toán tức thì… JVM tổ chức bộ nhớ nó cần để thực thi một chương
trình thành các vùng dữ liệu thời gian chạy. Đặc tả của máy ảo Java về các vùng này
là khá trừu tượng. Sự trừu tượng tự nhiên của đặc tả của vùng nhớ dữ liệu thời gian
chạy làm cho việc thực thi máy ảo java được dễ dàng hơn trên các thiết bị và các
máy tính.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 4

Một số vùng nhớ dữ liệu thời gian chạy được chia sẻ giữa các tiến trình của
ứng dụng, trong khi một số khác lại của riêng một số tiến trình. Mỗi thể hiện của
máy ảo java có một vùng dành cho các phương thức và một bộ nhớ heap. Những
vùng nhớ này được chia sẻ giữa các tiến trình chạy bên trong máy ảo. Khi máy ảo

Hình 12-2: Vùng dữ liệu thời gian chạy chia sẻ trong tất cả các luồng
tải một file lớp, nó phân tích thông tin một kiểu từ dữ liệu nhị phân chứa trong file
lớp và sau đó chuyển thông tin kiểu này vào trong vùng method area. Khi một
chương trình chạy thì máy ảo chuyển tất cả các đối tượng mà chương trình sinh ra
vào trong bộ nhớ heap.
Khi một luồng mới được tạo ra thì nó sẽ nhận một thanh ghi PC của chính nó
và một ngăn xếp Java. Nếu luồng này thực thi một phương thức java (không phải
một phương thức nguyên thuỷ) thì giá trị của thanh ghi PC sẽ chứa chỉ thị tiếp theo
để thực thi. Ngăn xếp Java chứa trạng thái của lời gọi phương thức java (không phải
lời gọi nguyên thuỷ) cho luồng đó. Lời gọi phương thức java bao gồm biến cục bộ
của nó, các tham số mà nó được gọi, giá trị trả về (nếu có) và kết quả tính toán trung
gian. Trạng thái của lời gọi phương thức nguyên thuỷ được chứa trong một ngăn

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 5

xếp phương thức nguyên thuỷ, giống như trong một thanh ghi hay trong một vùng
nhớ thực thi phụ thuộc.
Ngăn xếp Java được tạo nên bởi các stack frame (hay còn gọi là frame). Một
frame chứa trạng thái của một lời gọi hàm. Khi một luồng gọi một phương thức thì
máy ảo java sẽ đẩy (push) một frame mới vào trong ngăn xếp, và khi mà phương
thức hoàn thành thì máy ảo sẽ lấy và loại bỏ frame này ra.
Máy ảo java không có thanh ghi nào để chứa giá trị trung gian. Tập chỉ thị sử
dụng ngăn xếp java để chứa giá trị trung gian. Cách tiếp cận này được người thiết
kế tạo nên để giữ cho tập chỉ thị của máy ảo java được chặt chẽ rõ ràng và làm
thuận tiện cho việc thực thi trên kiến trúc với một vài hoặc các thanh ghi không có
mục đích thông thường. Ngoài ra thì kiến trúc dựa trên ngăn xếp của tập chỉ thị của
máy ảo java làm thuận tiện cho việc tối ưu mã làm việc được thực hiện bởi trình
biên dịch động và thời gian thực ( trình biên dịch này làm việc trong một số thực thi
của máy ảo java ).

12.2.1 Các kiểu dữ liệu.


Java có 2 kiểu dữ liệu đó là kiểu dữ liệu nguyên thuỷ và kiểu tham chiếu. Kiểu
dữ liệu nguyên thuỷ chứa các giá trị dữ liệu thực sự. Trong khi kiểu dữ liệu tham
chiếu thì tham chiếu đến một đối tượng dữ liệu.
Tất cả các kiểu dữ liệu nguyên thuỷ của ngôn ngữ lập trình Java đều là kiểu dữ
liệu nguyên thuỷ của máy ảo java. Mặc dù kiểu boolean là kiểu nguyên thuỷ nhưng
tập chỉ thị của máy ảo Java hỗ trợ một cách hạn chế kiểu này. Khi trình biên dịch
chuyển mã nguồn sang dạng Java bytecode thì nó dùng kiểu int hoặc byte để biểu
thị giá trị kiểu boolean ( 0 biểu thị false, giá trị khác 0 biểu diễn true). Giống như
ngôn ngữ lập trình java thì các kiểu nguyên thuỷ có miền giá trị không đổi trên các
nền tảng khác nhau. ( ví dụ kiểu long có độ dài 64 bit). Ngoài ra thì JVM còn làm
việc với một kiểu giá trị nguyên thuỷ mà ngôn ngữ lập trình Java không hỗ trợ đó là

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 6

Hình 12-3: Các kiểu dữ liệu của máy ảo java.


kiểu địa chỉ trả về (return address). Kiểu này dùng để thực thi mệnh đề finally trong
java.
Giá trị của kiểu tham chiếu chia làm 3 loại: kiểu lớp tham chiếu đến một thể
hiện của một lớp, kiểu interface tham chiếu đến một đối tượng của lợp mà thực thi
(implement) một giao diện, và kiểu array tham chiếu đến một đối tượng mảng.

12.2.2 Kích thước của từ.


Đơn vị cơ bản của kích cỡ dữ liệu trong máy ảo Java là từ, đây là kích thước
cố định được chọn bởi người thiết kế của mỗi thực thi của máy ảo java. Kích thước
của từ đủ lớn để chứa được một giá trị của các kiểu byte, int, char, float,
returnAddress hay tham chiếu. Hai từ phải đủ lớn để chứa một giá trị kiểu long hay

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 7

double. Do đó kích thước nhỏ nhất của từ là 32 bit. Nhưng thông thường nó được
chọn bằng kích thước của con trỏ nguyên thuỷ trên nền tảng máy chủ.
Đặc tả của nhiều vùng dữ liệu thời gian chạy của nhiều máy ảo java dựa trên
khái niệm trừu tượng của từ. Ví dụ hai đoạn của Java stack frame là biến cục bộ và
toán hạng được định nghĩa dựa trên thuật ngữ word. Những khu vực này có thể
chứa nhiều giá trị của bất kì kiểu dữ liệu nào của máy ảo java. Khi chúng được
chuyển vào vùng biến cục bộ và vùng toán hạng thì giá trị này sẽ chiếm một hoặc 2
từ.
Khi chạy thì chương trình Java không thể biết được kích thước của từ ( phụ
thuộc nền tảng bên dưới) nhưng kích thước này không ảnh hưởng đến hành vi của
chương trình.

12.2.3 Class Loader subsystem.


Đây là một phần của đặc tả máy ảo Java có nhiệm vụ tìm và tải các kiểu.Nó
gồm 2 dạng: boostrap class loader và user-defined class loader. Bootstrap class
loader là một bộ phận của một cài đặt máy ảo java trong khi user-defined class
loader lại là một phần của ứng dụng java đang chạy. Những lớp được tải bởi các bộ
tải này sẽ được chuyển vào trong một không gian tên riêng biệt bên trong máy ảo
java.
Class loader subsystem gọi nhiều bộ phận khác nhau của máy ảo Java và một
vài lớp của thư viện Java.lang. Ví dụ những user-defined class loader thông thường
là các đối tượng Java mà lớp của nó thừa kế từ Java.lang.classLoader. Những
phương thức của lớp ClassLoader cho phép ứng dụng Java truy cập vào cơ cấu các
lớp tải trong máy ảo. Cũng như vậy với mỗi kiểu mà Java tải, nó tạo ra một thể hiện
của lớp Java.lang.Class để thể hiện kiểu này. Giống như tất cả các đối tượng thì
user-defined class loader và các thể hiện của lớp Class cư trú ở trong bộ nhớ heap.
Dữ liệu của các kiểu được tải ở tỏng vùng phương thức methor area.
Quá trình tải, liên kết và khởi tạo.
Class loader subsystem không chỉ có trách nhiệm định vị và nhập dữ liệu nhị
phân cho các lớp. Nó còn phải kiểm tra tính đúng đắn của các lớp được nhập, cấp
phát và khởi tạo bộ nhớ cho các biến của lớp và trợ giúp trong việc chuyển của
tham chiếu biểu tượng. Các hoạt động trên được thưc thi trong một thứ tự nghiêm
ngặt:
1. Tải: Tìm và nhập dữ liệu nhị phân cho một kiểu
2. Liên kết: Thực thi việc xác minh, chuẩn bị và chuyển đổi

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 8

a. Xác minh: Để chắc rằng kiểu được nhập là đúng đắn


b. Chuẩn bị: Cấp phát bộ nhớ cho các biến của lớp, và khởi tạo bộ
nhớ cho giá trị mặc định
c. Chuyển đổi: Chuyển đổi tham chiếu biểu tượng từ kiểu vào
trong tham chiếu trực tiếp
3. Khởi tạo: Gọi mã Java mà khởi tạo cho các biến của lớp

Bootstrap Class Loader:


Các cài đặt của máy ảo Java phải có khả năng nhận ra và tải các lớp từ file nhị
phân mà phù hợp với định dạng file lớp Java. Một thực thi có thể nhận hay không
nhận ra các dạng nhị phân khác bên cạnh file lớp, nhưng bắt buộc phải nhận ra file
lớp.
Mỗi thực thi của máy ảo Java đều có một bootstrap class loader, cái mà biết
làm thế nào để tải các lớp cần thiết bao gồm các lớp của thư viện lập trình ứng dụng
Java (Java API). Đặc tả của máy ảo Java không định nghĩa làm thế nào mà bootstrap
class loader có thể định vị các lớp đấy. Người thiết kế thực thi phải quyết định việc
này.
Khi nhận được tên kiểu được nói rõ một cách đầy đủ thì BCL phải bằng một
số cách nào đó cố gắng đưa ra dữ liệu mà định nghĩa kiểu đấy. Một hướng tiếp cận
thông thường đó được giải thích trong thực thi máy ảo Java của Sun 1.1 cho Win98.
Nó tìm kiếm một đường dẫn thư mục người dùng định nghĩa được chứa trong biến
môi trường CLASSPATH. BCL sẽ tìm kiếm với mỗi thư mục ( theo thứ tự xuất hiện
trong biến CLASSPATH) cho đến khi nó tìm ra được một file với tên tương ứng: tên
đơn giản của kiểu cộng thêm “.class”. Trừ khi kiểu là bộ phận của một gói không
được đặt tên, bootstrap loader cho rằng nó ở trong một thư mục con của thư mục
trong biến CLASSPATH. Đường dẫn của thư mục con được xây dựng từ tên gói của
kiểu. Ví dụ nếu BCL đang tìm kiếm cho Java.lang.Object thì nó sẽ mong đợi
Object.class này trong thư mục java\lang là thư mục con của mỗi thư mục trong
CLASSPATH.
Trong phiên bản 1.2 thf BCP của Sun’s Java 2 SDK chỉ tìm trong thư mục mà
các file hệ thống (các file lớp của Java API) được cài đặt. Nó không tìm trong
CLASSPATH, thay vào đó việc tìm kiếm trong CLASSPATH là việc của bộ tải lớp
hệ thống (System class loader), một bộ tải lớp người dùng định nghĩa mà được tạo
ra tự động mỗi khi JVM bắt đầu.
User-define class loader (UCL).

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 9

Mặc dù UCL bản thân nó là một phần của ứng dụng Java, nhưng 4 phương
thức sau trong lớp ClassLoader là cửa ngõ để vào JVM.
ClassLoader:
− Protected final Class defineClass( String name,byte data[], int offset,
int length);
− Protected final Class defineClass(String name, byte data[], int offset,
int length, ProtectionDemain protectionDomain);
− Protected final Class findSystemClass( String name);

− Protected final void resolveClass( Class C);

Hai hàm đầu tiên định nghĩa lớp dựa vào các tham số như tên lớp, mảng dữ
liệu nhị phân, độ dịch (offset) và độ dài dữ liệu. Phương thức tiếp theo đưa ra thông
tin về lớp từ tên đầy đủ của lớp. Phương thức cuối cùng giúp JVM thực hiện liên kết
đến một lớp.

12.2.4 Vùng phương thức (Method area).


Bên trong máy một thể hiện của máy ảo Java thì thông tin về kiểu được tải
được chứa trong một vùng nhớ logic gọi là methor area. Khi máy ảo Java tải một
kiểu nó sử dụng một bộ tải lớp để định vị file lớp tương ứng. Bộ tải lớp đọc file lớp
đấy - thực chất là một luồng dữ liệu nhị phân, và chuyển qua máy ảo Java. Máy ảo
Java sẽ tách thông tin về chuỗi từ luồng dữ liệu nhị phân đấy và chứa thông tin này
trong vùng methor area. Các biến được khai báo trong lớp cũng được chứa trong
vùng nhớ này. JVM sẽ tìm kiếm và sử dụng thông tin về các kiểu trong miền methor
area khi nó thực thi ứng dụng. Do đó nhà thiết kế phải đưa ra được cấu trúc dữ liệu
tốt nhất để giúp cho tốc độ thực thi là cao nhất.
Tất cả các luồng cùng chia sẻ cùng một vùng methor area. Do đó việc truy cập
vào cấu trúc dữ liệu của vùng methor area phải được thiết kế để tạo ra sự an toàn. Ví
dụ khi 2 luồng cùng muốn tìm kiếm một lớp A nào đấy và lớp này chưa được tải,
thế thì chỉ có một luồng được quyền tải lớp A trong khi luồng còn lại phải chờ.
Kích thước của vùng methor area này cũng không nhất thiết phải cố định. Khi
chạy một chương trình thì nó có thể giãn ra hoặc co lại để phù hợp với chương
trình.
Vùng methor area cũng có thể được thu gom bộ nhớ rác (garbage collected).
Khi một lớp không còn được tham chiếu nữa thì máy ảo Java sẽ không tải lớp đó
nữa và quá trình thu dọn bộ nhớ xảy ra.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 10

Thông tin về kiểu.


Với mỗi kiểu mà nó tải thì JVM phải chứa những thông tin sau trong vùng
methor area:
− Full quatified name của kiểu.

− Full quatified name của lớp cha trực tiếp của nó ( trừ kiểu
java.lang.Object vì nó không có lớp cha)
− Kiểu này là lớp hay giao diện

− Bổ từ truy cập ( public , abstract, hay final)

− Danh sách có thứ tự của fully quatified name của bất kì giao diện trực
tiếp bên trên.
Bên trong file lớp và JVM thì tên của kiểu được chứa dưới dạng tên đầy đủ.
Trong mã nguồn thì tên đầy đủ có dạng tengoi.tenlop ví dụ java.lang.object. Còn
trong file lớp thì là java/lang/object. Đối với vùng methor area thì tên đầy đủ có thể
được thể hiện ở dạng form hoặc cấu trúc dữ liệu, tuỳ vào người thiết kế.
Ngoài các thông tin kể trên thì máy ảo còn phải chứa các thông tin sau cho
mỗi kiểu:
Danh sách các đối tượng dùng chung ( constant pool). Nó là một tập các hằng
được kiểu này sử dụng như String, integer,… và các tham chiếu đến các kiểu khác,
và các phương thức được sử dụng bởi kiểu này.
Thông tin về các trường bên trong. Các trường này cũng chứa trong vùng
methor area. Khai báo về thứ tự các trường này cũng phải được ghi lại. Thông tin về
mỗi trường bao gồm: tên trường, tên kiểu, bổ từ của trường ( public, private,
protected,..)
Thông tin về các phương thức. Giống như thông tin về các trường, nó cũng
bao gồm: tên phương thức, giá trị trả về, bổ từ của phương thức. Với mỗi phương
thức không phải là phương thức trừu tượng thì còn có thêm các thông tin: mã
bytecode của phương thức, cỡ của ngăn xếp toán hạng, và mục biến cục bộ của
stack frame của phương thức, bảng ngoại lệ.
Các biến của lớp được chia sẻ giữa tất cả các đối tượng của một lớp, nó kết
hợp với lớp chứ không phải là với một thể hiện của lớp. Vì thế một cách logic nó là
một phần của dữ liệu lớp và dĩ nhiên được chứa trong vùng methor area. Trước khi
JVM sử dụng một lớp thì nó phải cấp phát bộ nhớ cho mỗi biến của lớp, ngoại trừ
hằng biên dịch thời gian ( là biến của lớp được khai báo là final và giá trị chỉ được
xác định tại thời điểm biên dịch).

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 11

Một tham chiếu đến lớp ClassLoader. Với mỗi kiểu mà nó tải thì JVM phải
giữ liên hệ với kiểu đã được tải bởi bootstrap class loader hoặc user-define class
loader. Cho những kiểu được tải bởi user-defined class loader thì JVM phải chứa
một tham chiếu đến user-defined class loader mà đã tải kiếu đấy. Thông tin này
được chứa như là một phần của dữ liệu của kiếu trong vùng methor area. Máy ảo sử
dụng thông tin này trong suốt quá trình liên kết động. Khi một kiểu tham chiếu đến
một kiểu khác thì máy ảo sẽ yêu cầu kiểu được tham chiếu từ cùng một bộ tải lớp đã
tải kiểu đang tham chiếu. Kiểu sử lý này của liên kết động cũng là trung tâm của
cách thức mà máy ảo java hình thành nên các không gian tên riêng biệt. Để thực thi
một cách đúng đắn liên kết động và duy trì nhiều không gian tên khác nhau máy ảo
cần biết bộ tải lớp tưong ứng với mỗi kiểu trong vùng methor area. Chi tiết của liên
kết động và không gian tên được thảo luận chi tiết trong chương 8, “ Mô hình liên
kết”.
Một tham chiếu đến lớp Class ( java.lang.Class). một thể hiện của lớp
java.lang.Class được tạo bởi máy ảo java cho mỗi kiểu mà nó tải. JVM phải liên kết
một tham chiếu đến một thể hiện của lớp Class cho mỗi kiểu.
Bảng phương thức
Thông tin về kiểu phải được tổ chức bên trong methor area để có thể truy cập
được một cách nhanh chóng. Ngoài ra để tinh chế các thông tin đã nêu trước đây thì
các sự thực thi phải bao gồm cấu trúc dữ liệu khác mà có thể đẩy nhanh việc truy
cập đến dữ liệu cần tinh chế. Một ví dụ về cấu trúc dữ liệu kiểu này là bảng phương
thức. Với mỗi lớp không trừu tượng mà JVM tải thì nó có thể sinh một bảng
phương thức và bao gồm nó giống như là một phần của thông tin lớp được chứa
trong vùng methor area. Một bảng phương thức là một mảng của tham chiếu trực
tiếp đến tất cả các phương thức thể hiện mà có thể được gọi trong một thể hiện của
một lớp, bao gồm cả các phương thức thừa kế từ lớp cha. Một bảng phương thức
cho phép máy ảo Java nhanh chóng định vị một phương thức thể hiện được gọi trên
một đối tượng.

12.2.5 Bộ nhớ Heap.


Bất cứ khi nào một thể hiện lớp hoặc mảng được tạo ra trong lúc một ứng
dụng java đang chạy, bộ nhớ cho đối tượng mới được cấp phát từ một bộ nhớ heap
đơn. Giống như chỉ có một vùng Heap bên trong thể hiện một máy ảo Java, tất cả
các luồng đều chia sẻ nó. Bởi vì một ứng dụng Java chạy bên trong nó sở hữu độc
quyền thể hiện máy ảo java, ở đó có một vùng Heap riêng biệt cho mỗi ứng dụng
chạy riêng lẻ. Ở đó không có hai ứng dụng Java khác nhau lại có thể ghi đè lên nhau

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 12

dữa liệu vùng Heap. Tuy nhiên, hai luồng khác nhau của cùng1 ứng dụng, có thể
gây tác hại đối với vùng dữ liệu heap của luồng kia. Đây là tại sao mà bạn phải lo
lắng về sự đồng bộ hóa thích hợp truy cập đa luồng tới các đối tượng(dữ liệu bộ nhớ
Heap) trong chương trình java của bạn.
Máy ảo java có một chỉ lệnh mà cấp phát bộ nhớ trong vùng nhớ heap cho
một đối tượng mới, nhưng mà không có chỉ lệnh giải phóng cùng nhó đó. Đúng như
bạn không thể chỉ rõ việc giải phóng đối tượng trong mã nguồn Java và giải phóng
đối tượng trong Java bytecodes. Chính máy ảo chịu trách nhiệm quyết định có hay
không và khi nào giải phóng bộ nhớ bị chiếm bởi các đối tượng mà không còn liên
quan đến ứng dụng đang chạy. Thông thường sự thi hành bằng máy ảo java sử dụng
một bộ thu dọn giác để quản lý vùng heap.

12.2.6 Garbage Collection.


Chức năng chính của bộ thu dọn giác(garbage collector) là tự động phục hồi
bộ nhớ được sử dụng bởi các đối tượng mà không còn liên quan tới ứng dụng đang
chạy. Nó cũng có thể di chuyển các đối tượng khi ứng dụng chạy giảm bớt sự phân
mảnh vùng nhớ Heap.
Bộ thu dọn giác không hoàn toàn yêu cầu bởi sự đặc tả của máy ảo Java. Sự
đặc tả chỉ yêu cầu là quản lý thực thi trong vùng heap của chúng theo một cách nào
đó. Ví dụ một sự thi hành có thể đơn giản có một số lượng cố định của vùng trống
bộ nhớ heap sẵn có và một OutOfMemory ngoại lệ tung ra khi mà vùng trống được
phủ đầy.Trong khi sự đặc tả này có thể không đạt được mong ước nhiều, nó có đủ
tiêu chuẩn giống như một máy ảo java. Sự đặc tả bằng máy ảo java không nói số
lượng bộ nhớ sự đặc tả phải làm sẵn có để chạy các chương trình. Nó không nói một
sự đặc tả phải quản lý bộ heap như thế nào?Nó nói người thiết kế đặc tả duy nhất
chương trình sẽ được cấp phát bộ nhớ từ bộ nhớ heap, nhưng không giải phóng nó.
Đó là những người thiết kế tính đến họ muốn giải quyết thực tế đó như thế nào.
Không có kỹ thuật thu dọn giác được ra lệnh bởi sự đặc tả bởi máy ảo java.
Những người thiết có thể sử dụng bất cứ kỹ thuật gì thích hợp với những mục đích,
ràng buộc, tài năng của họ. Bởi vì những liên quan tới những đối tượng có thể tồn
tại ở nhiều nơi như: Java stacks, the heap, các vùng phương thức, sự lựa chọn kỹ
thuật thu dọn giác quá nhiều sẽ gây ảnh hưởng tới thiết kế vùng dữ liệu của sự đặc
tả. Các kỹ thuật thu dọn giác khác nhau sẽ được miêu tả trong chương 9, “Garbage
Collection”. Như vùng phương thức (methor area), bộ nhớ mà hình thành lên vùng
heap không cần phải liên tục và có thể mở rộng và co lại khi chương trình đang
chạy tiển triển. Thực ra vùng phương thức của sự đặc tả được thực hiện trên đỉnh bộ

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 13

nhớ heap của nó. Nói cách khác khi máy ảo cần bộ nhó cho một lớp được nạp mới,
nó có thể lấy bộ nhớ từ cùng một heap mà trên đó các đối tượng đang cư chú. Cùng
bộ thu dọn rác mà giải phóng bộ nhớ đang bị chiếm giữ bởi những đối tượng không
còn liên quan có thể chú ý tới kết quả tìm kiếm và giải phóng những lớp không còn
liên quan nữa. Các cài đặt có thể cho phép những người sử dụng hoặc lập trình viên
chỉ định một kích thước ban đầu cho bộ nhớ heap, cũng như một kích thước tối đa
và tối thiểu.
Object Representation(Mô tả đối tượng)
Đặc tả máy ảo java ít đề cập cách làm thế nào các đối tượng thể hiện trên
heap. Mô tả đối tượng- một khía cạnh phân tích của toàn bộ thiết kế của heap và thu
hồi bộ nhơ- là quyết định của người thiết kế thực thi.
Dữ liệu chính mà trong cách thể hiện của mỗi đối tượng là những biến trong
khai báo lớp của đối tượng hoặc lớp cha của nó. Khi nhận được một tham chiếu đến
một đối tượng thì JVM phải có khả năng định vị nhanh dữ liệu cho đối tượng.
Ngoài ra, phải có cách nào đó để truy cập được lớp dữ liệu lớp của đối tượng (lưu
trữ trong vùng phương thức) đưa cho việc tham chiếu tới đối tượng. Lý do này, bộ
nhớ được cấp phát cho đối tượng thông thường bao gôm một số kiểu con trỏ vào
trong vùng phương thức.
Một khả năng thiết kế heap là có thể chia heap thành 2 phần: một vùng điều
khiển và một vùng đối tượng. Một tham chiếu đối tượng là một con trỏ có sẵn trỏ
tới mục ở vùng điều khiển. Cái handle pool ( vùng quản lý chung) gồm 2 bộ phận:
một con trỏ liên kết đến dữ liệu cài đặt trong vùng object pool ( các đối tượng
chung) và một con trỏ đến dữ liệu của lớp đặt trong vùng methor area( vùng phương
thức). Ưu điểm của mô hình này là nó làm cho máy ảo java dễ dàng chống lại sự
phân mảnh của bộ nhớ heap. Khi máy ảo Java chuyển một đối tựong trong vùng đối
tựong chung, nó chỉ cần cập nhật một con trỏ với một địa chỉ mới của đối tựong:
con trỏ thích hợp trong vùng quản lý chung. Hạn chế của phương pháp này là mỗi
lần truy cập tới một thực thể dữ liệu của đối tượng yêu cầu hai con trỏ. Cách tiếp
cận mô tả đối tượng này được thể hiện bằng đồ thị cho trong hình 12-5. Loại heap
này giải thích sự tương tác bởi HeapOfFish applet, miêu tả trong Chương 9,
“Garbage Collection”

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 14

Hình 12-4: Splitting an object across a handle pool and object pool.
Một thiết kế khác thì một tham chiếu đến đối tượng là một con trỏ cơ sở
tham chiếu đến một gói dữ liệu chứa các dữ liệu của đối tượng và một con trỏ trỏ
đến dữ liệu lớp của đối tượng đấy. Hướng tiếp cận này chỉ yêu cầu chỉ một con trỏ
truy nhập tới dữ liệu thể hiện của một đối tượng, nhưng việc di chuyển đối tượng
phức tạp hơn. Khi máy ảo di chuyển một đối tượng để tránh sự phân mảnh của loại
heap này, nó phải cập nhật mọi sự tham chiếu tới đối tượng đó bất cứ nơi đâu trong
những vùng dữ liệu khi chạy. Cách tiếp cận này miêu tả đối tượng được thể hiện
bằng đồ thị trong hình 12-5.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 15

Hình 12-5: Dữ tất cả các đối tượng dữ liệu trong một vùng trống.
Một điều chú ý nữa là việc sử dụng bảng phương thức trong việc tăng tốc việc
gọi các phương thức của đối tượng=> Giúp cho máy ảo Java đạt hiệu suất cao.
Nó không nằm trong những yêu cầu bắt buộc của đặc tả máy ảo Java.=>
không phải mọi cài đặt đều phải có cái này. Những thực thi mà có bộ nhớ thấp có
thể không đáp ứng được yêu cầu bộ nhớ của bảng phương thức.
Một cách để một thực thi có thể kết nối đến một bảng phương thức được cho
như hình vẽ.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 16

Hình 12-6: Keeping the method table close at hand


Một kiểu dữ liệu khác không được thể hiện trên hình 12.4 và 12-5 là khóa
( hay mutex). Nó là một chương trình ở trong bộ nhớ heap dùng để quản lý đồng bộ
hóa đa luồng cùng truy cập vào một tài nguyên.
Một ví dụ sau cùng của một kiểu dữ liệu mà có thể là một phần của đối tựong
trong bộ nhớ heap là những dữ liệu cần thiết cho bộ thu gom rác.Bộ thu gom rác
phải có cơ chế theo dõi những đối tượng được tham chiếu bởi chương trình. Kiểu
dữ liệu phụ thuộc vào kĩ thuật cài đặt cho bộ thu gom rác. Ví dụ một bộ thu gom rác
sử dụng thuật toán đánh dấu và quét (mark and sweep), nó phải có khả năng đánh
dấu đối tượng là tham chiếu hay không tham chiếu. Và như vậy một bản đồ bit là
cần thiết cho mỗi đối tượng.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 17

Biểu diễn mảng.

Hình 12-7: One possible heap representation for arrays.

Trong Java thì mảng là một đối tượng thực sự. Giống các đối tượng khác thì
nó cũng được lưu trữ trong vùng nhớ heap.
Các đối tượng có cùng chiều và kiểu các phần tử thì thuộc cùng một lớp.
Tên lớp của một mảng có cấu trúc là một dấu ngoặc vuông mở cộng với một
chữ cái biểu diễn lớp
Vd: mảng 3 phần tử int có tên lớp là “[I”. Mảng 2 chiều gồm các đối tượng có
tên lớp là “[[java.lang.Objects”. Mảng n chiều là mảng của các mảng n-1 chiều.
Dữ liệu lưu giữ cho trên bộ nhớ heap cho mỗi mảng là độ dài mảng, dữ liệu
mảng, và một vài kiểu của tham chiếu đến dữ liệu lớp của mảng. Khi nhận được
một tham chiếu đến mảng thì JVM có thể truy cập đến các phần tử của mảng qua

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 18

chỉ mục, và có thể gọi bất cứ hàm nào của lớp Object, là lớp cha trực tiếp của lớp
đối tượng mảng.
Thanh ghi đếm chương trình
Mỗi một luồng của một chương trình thì có thanh ghi PC của nó, thanh ghi PC
được khởi tạo lúc luồng được tạo. Nó có kích thước 1 từ, do đó nó có thể chứa cả
con trỏ cơ sở và giá trị trả về. Khi một luồng thực thi một phương thức thì PC sẽ
chứa chỉ thị hiện tại đang thực thi bởi luồng. Địa chỉ ở đây có thể là con trỏ cơ sở
hoặc độ dịch offset so với địa chỉ bắt đầu của mã bytecode của phương thức. Nếu
một luồng thực thi một con trỏ cơ sở thì giá trị của PC là không được định nghĩa
(undefined).

12.2.7 Ngăn xếp Java


Khi một luồng mới được thực thi, thì một ngăn xếp Java sẽ được tạo ra ứng
với luồng đó.
Máy ảo Java lưu trữ trạng thái của luồng thành các frame riêng biệt.
Máy ảo Java chỉ thực hiện được hai thao tác trên stack này là push() và pop()
các khung này.
Phương thức hiện tại được thực hiện bởi luồng gọi là phương thức hiện thời
( current method ) của luồng. Khung lưu trữ hiện tại cho phương thức hiện tại là
khung hiện thời ( current frame ). Lớp chứa phương thức đang được thực thi hiện
thời là lớp hiện thời ( current class ). Và vùng hằng số của lớp đó gọi là vùng hằng
số hiện thời ( current constant pool). Khi thực thi phương thức thì máy ảo Java sẽ
lưu giữ dấu vết của lớp hiện tại và vùng hằng số hiện tại. Khi máy ảo Java thực thi
chỉ lệnh trên dữ liệu được lưu ở stack frame thì nó thực hiện trên khung hiện tại
( current frame).
Khi một luồng gọi phương thức, thì máy ảo Java sẽ thực hiện đẩy một frame
mới lên ngăn xếp, và trở thành ngăn xếp hiện tại.
Một phương thức có thể sẽ trả về giá trị sau khi hoàn thành thực thi ( gọi là
phương thức kết thúc bình thường), hoặc khi ném ra ngoại lệ thì sẽ là kết thúc bất
thường.
Tất cả dữ liệu lưu trữ trong ngăn xếp Java là riêng đối với luồng đó. Các luồng
không thể thay đổi hoặc truy cập tới dữ liệu của các luồng khác. Chỉ luồng gọi
phương thức đó mới có thể truy cập vào biến ở frame được tạo ra khi luồng gọi.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 19

Frame có thể được cấp phát ở vùng nhớ liên tục của ngăn xếp hoặc ở vùng nhớ
động heap. Cấu trúc dữ liệu thực sự của ngăn xếp Java và stack frame phụ thuộc
vào những người thiết kế cài đặt.
12.2.7.1 Stack frame
Khung ngăn xếp có 3 phần: các biến cục bộ, ngăn xếp toán hạng và dữ liệu
khung. Kích thước của các biến cục bộ, ngăn xếp toán hạng được tính toán bằng số
lượng từ ( word), được xác định vào thời điểm biên dịch, được ghi lại trong các file
.class của mỗi phương thức. Còn kích thước của dữ liệu khung phụ thuộc vào chi
tiết cài đặt, được xác định tại thời điểm thực thi, khôgn thể thay đổi
Vùng biến cục bộ
Được tổ chức thành mảng các từ zero-based. Khi chỉ lệnh nào sử dung giá trị
biến nào đó thì sẽ cung cấp chỉ số cho các thành phần trong mảng để trỏ tới dữ liệu
đó.
Trước hết, các tham số của phương thức sẽ được lưu vào theo thứ tự khai báo.
Sau đó các biến cục bộ có thể được lưu vào tiếp sau, không cần theo thứ tự
Các kiểu dữ liệu int, float, reference và returnAddress chiếm một mục trong
mảng đó.
Còn kiểu long, double chiếm 2 mục trong mảng.
Giá trị kiểu char, byte, short được chuyển thành kiểu int trước khi lưu vào
vùng biến cục bộ.
Ví dụ:
public static int runClassMethod(int i, long l,
float f,
double d, Object o, byte b) {
return 0;
}
public int runInstanceMethod(char c, double d, short
s,
boolean b) {

return 0;
}

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 20

Hình 12-8: Method parameters on the local variables section of a Java stack.
Trong hình trên, ta thấy tham số đầu tiên trong vùng biến cục bộ của phương
thức runInstanceMethod() có kiểu tham chiếu reference mặc dù trong đoạn mã
nguồn không có tham số nào như vậy. Đây là tham số ẩn, được truyền vào đối với
mỗi thể hiện của phương thức. Phương thức thể hiện này sử dụng tham số ẩn đó để
truy cập tới các dữ liệu thể hiện của đối tượng dựa trên những gì chúng được gọi.
Vì phương thức static không có tham số nào như thế, nên ta không thể truy cập
tới dữ liệu thể hiện của lớp vì khôgn có thực thể nào gắn với lời gọi phương thức
đó.
Các kiểu byte, short, char và boolean trong mã nguồn trở thành kiểu int trong
vùng biến cục bộ và ngăn xếp toán hạng. Các kiểu dữ liệu hỗ trợ trực tiếp bởi máy
ảo Java có thể được lưu trữ trên heap như các thể hiện của biến hoặc thành phần của
mảng hoặc trong vùng nhớ phương thức như biến của lớp. Các kiểu dữ liệu được
chuyển thành int cũng sẽ được chuyển lại thành nguyên gốc trước khi lưu lại vào
trong vùng heap hoặc trong vùng phương thức.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 21

12.2.7.2 Ngăn xếp toán hạng


Các thành phần của ngăn xếp toán hạng được truy cập theo các phương thức
push() và pop(). Ngoài con đếm chương trình, máy ảo Java không có thanh ghi.
Máy ảo Java dựa vào stack hơn là thanh ghi, bởi vì:
Các chỉ lệnh của nó lấy toán hạng từ ngăn xếp toán hạng, không lấy từ thanh
ghi. Các chỉ lệnh cũng có thể lấy toán hạng từ các vùng khác như: lấy trực tiếp từ
các opcode tiếp theo trong luồng byte, hoặc từ vùng hằng số.
Ví dụ về việc sử dụng ngăn xếp toán hạng là nơi làm việc của máy ảo Java:
Iload_0
Iload_1
Iadd
Istore_2
Hai chỉ lệnh đầu tiên, đẩy giá trị int vào vị trí biến cục bộ số 0, 1 trên ngăn xếp
toán hạng. Chỉ lệnh iadd lấy hai giá trị int này, cộng chúng, và đẩy kết quả int trở lại
ngăn xếp toán hạng. Chỉ lệnh thứ tư, istore_2 lấy giá trị tổng khỏi đỉnh ngăn xếp
toán hạng và lưu nó vào trong vị trí biến cục bộ thứ 2.

Hình 12-9: Adding two local variables.


12.2.7.3 Frame data
Vùng dữ liệu khung của khung ngăn xếp Java chứa những dữ liệu:
− Dữ liệu hỗ trợ cho việc chỉ định tới vùng hằng số

− Kết quả trả về của phương thức bình thường

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 22

− Và gửi các ngoại lệ.

Rất nhiều chỉ lệnh trong tập lệnh của máy ảo Java chỉ dẫn tới vùng hằng số.
Những chỉ lệnh này đẩy các giá trị hằng số kiểu int, long, float, double, hoặc string
từ vùng hằng số lên ngăn xếp toán hạng. Một vài chỉ lệnh này sử dụng các mục ở
vùng hằng số để chỉ dẫn tới các lớp hoặc mảng, tới ví dụ, trường dữ liệu để truy cập
hoặc phương thức được gọi. Các chỉ thị khác xác định liệu đối tượng riêng biệt là
thừa kế từ lớp riêng biệt hoặc giao diện hay không được chỉ ra bởi các mục trong
vùng hằng số.
Khi máy ảo Java gặp bất cứ câu lệnh nào chỉ tới vùng constant pool, nó sử
dụng con trỏ của khung ngăn xếp tới vùng đó. Khi tham chiếu tới các kiểu dữ liệu ở
vùng đó thì tức là khi đó khởi đầu kí tự, và máy ảo Java phải xử lý tham chiếu này
tại thời điểm đó.
Bên cạnh đó, dữ liệu khung cũng phải tham gia trong việc xử lý sự kết thúc
bình thường hoặc bất thường của một phương thức. Nếu phương thức kết thúc bình
thường, thì máy ảo phải trả lại khung ngăn xếp (có cả dữ liệu khung) của lời gọi
phương thức đó. Nó phải đặt thanh ghi pc trỏ tới câu lệnh trong phương thức được
gọi theo sau chỉ lệnh gọi sự hoàn thành của phươgn thức. Nếu phương thức trả về
giá trị, máy ảo phải đẩy kết quả lên ngăn xếp toán hạng của phương thức được gọi
đó.
Khung dữ liệu có thể gồm một vài tham chiếu tới bảng ngoại lệ của phương
thức, được máy ảo sử dụng để xử lý bất cứ ngoại lệ nào được ném ra trong quá trình
thực thi của phương thức đó. ( Chi tiết về ngoại lệ được nêu ở chương 17). Mỗi mục
trong bảng ngoại lệ có điểm đầu và điểm cuối của phạm vi mệnh đề catch, một chỉ
số trong vùng hằng số chỉ tới lớp ngoại lệ được bắt, và vị trí đầu của mã mệnh đề
catch.
Khi phương thức ném ra ngoại lệ, máy ảo Java sử dụng bảng ngoại lệ được chỉ
ra bởi dữ liệu khung để xác định cách điều khiển ngoại lệ đó. Nếu máy ảo tìm thấy
mệnh đề catch phù hợp thì nó sẽ chuyển quyền điều khiển cho điểm bắt đầu mệnh
đề catch. Nếu không, phương thức sẽ kết thúc bất thường.
Ngoài ra, khung ngăn xếp cũng có thể chứa các thông tinh khác, phụ thuộc vào
cài đặt: như dữ liệu hỗ trợ gỡ lỗi.
Chi tiết cài đặt của ngăn xếp Java
Xem ví dụ như sau:
class Example3c {

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 23

public static void addAndPrint() {


double result = addTwoTypes(1, 88.88);
System.out.println(result);
}

public static double addTwoTypes(int i, double d) {


return i + d;
}
}
Hình vẽ trực quan cho đoạn mã nguồn trên có thể minh họa như sau:

Hình 12-10: Allocating frames from a heap.


Trong cài đặt ở trên, mỗi frame được cấp phát riêng rẽ trong vùng heap
( không liên tục)
Để gọi phương thức addTwoType(), phương thức addAndPrint() trước hết phải
đẩy giá trị int và double lên ngăn xếp toán hạng. Sau đó gọi phương thức
addTwoType().

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 24

Chỉ lệnh gọi phương thức addTwoType() chỉ dẫn tới vùng hằng số. Máy ảo sẽ
tìm kiếm và giải quyết các vấn đề cần thiết trước khi sử dụng phương thức đó. Mặc
dù tham chiếu tới các phương thức, trường khác của lớp thì ở cùng một lớp, tham
chiếu trong vùng hằng số bao giờ cũng được khởi tạo là kí hiệu và được xử lý trước
khi thực hiện thực thi tiếp theo.
Việc xử lý này thực chất là tìm thông tin trong vùng hằng số chỉ tới thông tin
của phương thức trong vùng phương thức. Sau đó máy ảo Java sẽ sử dụng thông tin
đó xác định kích thước của phương thức này (addTwoType() ). (Có thể trên nền
SDK thì kích thuơc vùng biến cục bộ của phương thức này yêu cầu 3 từ nhớ, và 4 từ
nhớ của ngăn xếp toán hạng)
Khi phương thức addTwoType thực thi, nó sẽ lấy 2 giá trị vùng ngăn xếp toán
hạng của phương thức gọi (addAndPrint() ) đặt vào vùng biến cục bộ. Khi lấy giá trị
trả về thì kết quả được lưu trong stack toán hạng của phương thức addTwoType().
Dựa vào dữ liệu khung, phương thức hiện thời (addTwoType ) sẽ định vị phương
thức gọi nó ( addAndPrint) và giải phóng phương thức hiện thời, quay trở lại tiếp
tục thực thi phương thức gọi nó.
Một cách thực thi khác của đoạn mã nguồn giống ở trên là sử dụng cấp phát
liên tục trong stack.. Trong cách cài đặt này, toàn bộ ngăn xếp toán hạng của
phương thức addAndPrint() trở thành phần biến cục bộ của phương thức
addTwoType():

Hình 12-11: Allocating frames from a contiguous stack.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 25

12.2.7.4 Ngăn xếp phương thức cơ sở


Các ứng dụng Java ngoài việc sử dụng các dữ liệu được tạo ra bởi những vùng
dữ liệu thời gian chạy được đặc tả bởi máy ảo Java như đã nghiên cứu ( heap, vùng
phương thức, constant pool …) thì còn có thể lấy dữ liệu được cung cấp bởi ngăn
xếp phương thức cơ sở. Các phương thức cơ sở này có thể truy cập tới dữ liệu ở
vùng thực thi, các thanh ghi trong bộ vi xử lý, hoặc cấp phát ở phần nào đó của
heap cơ sở.hoặc bất cứ ngăn xếp nào.
Chi tiết cài đặt phương thức cơ sở tùy vào người thiết kế cài đặt.
Bất cứ giao diện phương thức cơ sở cũng sử dụng vài ngăn xếp phương thức
cơ sở.
Khi một luồng gọi phương thức cơ sở thì nó sẽ để ngăn xếp Java ở bên dưới,
liên kết dộng tới phương thức cơ sở này và trực tiếp gọi phương thức cơ sở đó.
Và một phương thức cơ sở cũng sẽ có thể được gọi lại vào máy ảo Java và gọi
một phương thức Java. Trong trường hợp này, luồng sẽ bỏ lại ngăn xếp phương thức
cơ sở và bắt đầu vào một ngăn xếp Java khác.
Hình vẽ sau minh họa ví dụ việc thực thi chương trình Java có gọi tới phương
thức cơ sở, sau đó được gọi lại trở lại phương thức Java:

Hình 12-12: The stack for a thread that invokes Java and native methods.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 26

Cũng giống như vùng nhớ thời gian chạy khác, vùng nhớ của ngăn xếp
phương thức cơ sở không cần có kích thước cố định. Một vài cài đặt có thể cho
phép người sử dụng và các nhà lập trình chỉ ra kích thước khởi đầu của vùng
phương thức cũng như kích thước tối thiểu và tối đa của nó.

12.2.8 Máy thực thi


Máy thực thi là cốt lõi của cài đặt máy ảo Java. Trong đặc tả máy ảo java,
hành vi của máy thực thi được định nghĩa bằng thuật ngữ một tập chỉ thị. Đối với
mỗi chỉ thị, đặc tả chỉ ra chi tiết một cài đặt cần phải làm gì ( what ) khi nó gặp chỉ
lệnh đó như : thực thi bytecode, nhưng nó hầu như không nói về cách làm thế nào
với chỉ lệnh đó. Người thiết kế cài đặt có quyền quyết định sẽ thực thi bytecode như
thế nào: Hoặc là thông dịch, biên dịch just-in-time, thực thi tự nhiên trên phần cứng
(silicon) hoặc sử dụng kết hợp hay một kĩ thuật mới nào đó.
Máy thực thi cũng có thể hiểu theo 3 nghĩa sau đây:
+ một đặc tả trừu tượng, ( định nghĩa hành vi của máy thực thi theo nghĩa một
tâp chỉ thị )
+ cài đặt cụ thể ( cài đặt phần cứng hoặc phần mềm, hay kết hợp cả hai ) , hay
+ thể hiện thời gian chạy ( chính là luồng ). Mỗi luồng thuộc về một ứng dụng
thời gian chạy, chính là máy thực thi lúc hoạt động ( execution engine in action).
12.2.8.1 Tập chỉ lệnh
Mỗi chỉ lệnh gồm một mã toán tử (opcode) một byte, có thể theo sau là một
hoặc nhiều hay khôgn có toán hạng nào. Mỗi opcode xác định thao tác cần thực
hiện. Mỗi toán hạng cung cấp thông tin thêm cho máy ảo Java thực hiện thao tác cụ
thể nào đó.
Khi thực thi chỉ lệnh nào đó, nó có thể lấy toán hạng từ các lối vào của vùng
hằng số hiện tại, lối vào của vùng biến cục bộ của khung hiện tại, hoặc giá trị trên
đỉnh ngăn xếp toán hạng của khung hiện tại.
Mỗi máy thực thi trừu tượng chỉ thực thi một chỉ lệnh tại một thời điểm. Khi
thực hiện quá trình xử lý chỉ lệnh thì nó sẽ nạp một opcode trước, sau đó là các toán
tử ( nếu cần thiết ), và chỉ lệnh tiếp theo. Việc thực thi bytecode tiếp tục cho tới khi
luồng hoàn thành.
Một phươgn thức cơ sở có thể coi là phần mở rộng tùy chọn của người lập
trình đối với tập chỉ lệnh.
Việc xác định chỉ lệnh tiếp theo theo ba cách :

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 27

− Chính là phần thực thi tiếp theo của opcode hiện tại

− Dựa vào chỉ lệnh như goto, return.

− Tìm kiếm mệnh đề catch phù hợp ( nếu chỉ thị là ném ngoại lệ)

Các chỉ lệnh có thể ném ngoại lệ :


athrow ( ném ngoại lệ rõ ràng ), idiv, ldiv, irem, lrem ( biểu diễn phép chia
hoặc phần dư trên các số nguyên hoặc long ).

Các luồng bytecode có thể phân chia thành các đoạn gợi nhớ.
Trọng tâm của tập chỉ lệnh của máy ảo Java là ngăn xếp toán hạng.
Các tập chỉ thị được coi như các biến cục bộ, hoặc như tập thanh ghi được
tham chiếu bởi chỉ số.
Việc thiết kế tập chỉ lệnh máy ảo Java:
Mục tiêu cần trong thiết kế là độc lập nền, khả chuyển mang tính hệ
thống, và an toàn.
Để đạt được đọc lập nền, việc cà i đặt máy ảo Java được thực hiện dễ dàng trên
phạm vi lớn các kiến trúc máy khác nhau: hướng ngăn xếp.
Kiến trúc hướng ngăn xếp của tập chỉ lệnh máy ảo Java làm việc tối ưu hóa dễ
dàng, có thể thực hiện tại thời gian chạy cùng với máy thực thi thực hiện việc biên
dịch JIT hoặc tối ưu thích nghi ( adaptive optimization ).
Để đạt được tính khả chuyển hệ thống: Để tăng tốc độ truyền file qua mạng
nên việc thu gọn file rất quan trọng. Do đó thiết kế sao cho tổng số mã toán tử
(opcode) chỉ cần biểu diễn trong 1 byte.
Để đạt được tính an toàn thì cần xác minh các bytecode. Việc xác minh có thể
được thực hiện trên từng chỉ lệnh hoặc trên dòng dữ liệu. Do đó hầu hết các opcode
nên xác định trước các kiểu dữ liệu mà chúng sẽ thực hiện thao tác trên đó.
12.2.8.2 Kĩ thuật thực thi
Có một vài kĩ thuật phổ biến có thể sử dụng là
− Thông dịch

− Biên dịch Just-in-time

− Tối ưu thích nghi

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 28

− Thực thi trực tiếp trên silicon

Kĩ thuật tối ưu thích nghi có rất nhiều ưu điểm, và sẽ được mô tả chính ở đây.
Việc tối ưu thích nghi sẽ tận dụng được thông tin chỉ có trong thời gian thực thi.
Kĩ thuật này bắt đầu thông dịch toàn bộ mã, nhưng sẽ tập trung vào cách điều
chỉnh việc thực thi của mã. Máy ảo java có thể định hình phương thức thể hiện điểm
“hot-spot” của chương trình: khoảng 10-20 % mã được thực thi trong 80-90 % thời
gian. Sau khi xác định điểm “hot-spot”, nó sẽ gọi lại tiến trình nền biên dịch những
đoạn mã này thành cơ sở và tập trung tối ưu thành mã cơ sở (có thể thực thi được
ngay, nhanh chóng). Vì chỉ cần tập trung biên dịch và tối ưu “hot-spot” nên có thêm
thời gian tối ưu nữa. Sau đó một phương thức có thể di chuyển ra ngoài “hot-spot”,
máy ảo sẽ loại bỏ mã đó, và trở lại thông dịch chúng. Không giống như máy ảo biên
dịch JIT , kĩ thuật này không thực hiện việc tối ưu sớm. Mà nó chỉ bắt đầu từ
bytecode thông dịch được. Khi chương trình chạy, máy ảo “profile” chương trình để
tìm ra “hot spot”.
Giao diện phương thức cơ sở
Cài đạt máy ảo Java không yêu cầu hỗ trợ bất cứ giao diện phương thức cơ sở
đặc biệt nào. Một vài cài đặt có thể hỗ trợ hoặc không. Ví dụ: Giao diện cơ sở Java
của SUN, JNI được kết hợp để hỗ trợ tính khả chuyển. Điều này cho phép các nhà
phát triển có thể liên kết các mã nhị phân của phương thức cơ sở giống nhau tới bất
cứ cài đặt máy ảo nào hỗ trợ JNI, trên một nền máy chủ đặc biệt.
Để đạt được mục tiêu đó, người thiết kế có thể quyết định đưa ra giao diện
phương thức cơ sở ở mức độ thấp tương đối gắn chặt với cấu trúc của thực thi riêng
biệt của họ.
Mỗi phương thức cơ sở phải có thể tương tác ở mức độ nào đó với trạng thái
bên trong thực thể máy ảo Java. Ví dụ, giao diện có thể hỗ trợ một vài hoặc tất cả
các thao tác:
− Truyền vào và trả lại dữ liệu

− Truy cập tới thể hiện của biến hoặc gọi phương thức của đối tượng trên
vùng heap được thu gom bộ nhớ
− Truy cập biến của lớp hoặc gọi phương thức lớp

− Truy cập mảng

− Khóa đối tượng trên vùng heap để luồng hiện thời sử dụng độc quyền

− Tạo mới đối tượng trên vùng heap được thu gom bộ nhớ

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 29

− Tải các lớp mới

− Ném một ngoại lệ

− Bắt ngoại lệ ném bởi phương thức Java mà được gọi từ phương thức cơ
sở
− Bắt ngoại lệ không đồng bộ ném bởi máy ảo

− Xác định việc không cần thiết thu gom bộ nhớ với các đối tượng đặc
biệt.

Việc thiết kế giao diện phương thức cơ sở đòi hỏi một số dịch vụ phức tạp
− Phải đảm bảo bộ thu hồi bộ nhớ không được giải phóng bất cứ đối tượng
nào đang được dùng bởi phương thức cơ sở
− Nếu phải di chuyển đối tượng để giữ sự phân mảng heap ở mức nhỏ
nhất, thì phải đảm bảo một trong hai điều kiện:
1. Đối tượng có thể di chuyển sau khi tham chiếu được truyền vào một
phương thức cơ sở
2. Bất cứ đối tượng nào mà tham chiếu được truyền vào phương thức cơ
sở được giữ chặt cho tớikhi trả về giá trị hoặc xác định nó được hoàn
thành với một đối tượng.

Nhóm 12 - Java Virtual Machine – K49CNPM


Java Virtual Machine 30

TÀI LIỆU THAM KHẢO


Tiếng Anh
1. Inside the Java Virtual Machine.

Nhóm 12 - Java Virtual Machine – K49CNPM

You might also like