1. Giới thiệu về kiến trúc JVM

JMV – Java Virtual Machine là một máy ảo Java – trình thông dịch Java. Đây là môi trường để chạy được ứng dụng được viết bằng ngôn ngữ lập trình Java. Chương trình Java khi biên dịch sẽ tạo ra các file *.class chứa byte code , các file *.class này sẽ được JVM thực hiện chuyển byte code thành mã máy tương ứng với từng hệ điều hành và phần cứng khác nhau thực thi.

Trong các ngôn ngữ lập trình khác, trình biên dịch (compiler) tạo mã máy cho một hệ thống cụ thể. Tuy nhiên, trình biên dịch Java (Java Compiler) tạo mã cho một máy ảo được gọi là Máy ảo Java (JVM). Đầu tiên, mã Java được tuân thủ theo bytecode . Bytecode này được diễn giải trên các máy khác nhau giữa hệ thống máy chủ và Java Source , Bytecode là ngôn ngữ trung gian.

2. Cấu trúc bên trong JVM

Các thành phần chính của JVM đó là:

  • Class Loader : là một hệ thống con của JVM, làm nhiệm vụ tải các lớp được định nghĩa. Nó thực hiện ba chức năng chính: Loading , LinkingInitialization (Khởi tạo)
  • Class Area : lưu trữ cấu trúc của các lớp, thuộc tính, phương thức của lớp, và code của các phương thức.
  • Heap : là vùng nhớ lưu trử các đối tượng được khởi tạo trong quá trình thực thi.
  • Stack : chứa các frame . Mỗi frame chứa các biến cục bộ và thực thi một hàm gọi và trả kết quả về. Mỗi tiến trình có một Stack riêng, được khởi tạo cùng lúc với tiến trình. Mỗi frame sẽ được tạo khi một hàm được gọi và hủy khi việc gọi hàm kết thúc.
  • Programming Counter Register : chứa địa chỉ của máy chủ ảo đang thực thi
  • Native Method Stack : chứa các hàm của hệ thống được sữ dụng trong chương trình
  • Execution Engine : là một hệ thống bao gồm: bộ xử lý ảo, trình thông dịch (đọc Java byte code và thực thi các chỉ thị), JIT compiler biên dịch mã byte code sang mã máy. Các nhiệm vụ chính của JVM bao gồm: tải code, kiểm tra code, thực thi code, cung cấp môi trường runtime.

3. Cách thức hoạt động của JVM

Trước tiên, để viết và thực hiện chương trình phần mềm, ta cần có những điều sau đây:

  • Editor – Để nhập chương trình vào, có thể sử dụng notepad cho trình biên dịch
  • Compiler – Để chuyển đổi chương trình ngôn ngữ cao thành mã máy gốc
  • Linker – Để kết hợp các tệp chương trình khác nhau trong chương trình chính của ta với nhau.
  • Loader – Để tải các tệp từ thiết bị lưu trữ thứ cấp như Đĩa cứng, Flash Drive, CD vào RAM để thực thi. Việc tải được tự động thực hiện khi ta thực thi mã
  • Execution – Thực thi mã được xử lý bởi hệ điều hành & bộ xử lý

Sau đó JVM sẽ thực hiện các công việc sau:

  • Loads code – tải mã lệnh
  • Verifies code – Kiểm tra mã lệnh
  • Executes code – thực thi mã lệnh
  • Provides runtime environment – công cấp môi trường biên dịch mã

JVM đã cung cấp định nghĩa cho

  • Memory area – vùng nhớ
  • Class file format – Định dạng các class
  • Register set – setup đăng ký
  • Garbage-collected heap – Xóa dữ liệu rác
  • Fatal error reporting – Tổng hợp báo cáo

4. Module chính trong JVM

JVM được chia thành 3 module chính:

  • Class-Loader Subsytem : chuyên tìm kiếm và load các file .class vào vùng nhớ của Java.
  • Runtime Data Area : vùng nhớ hệ thống cấp phát cho JVM
  • Execution Engine : chuyển các lệnh của JVM trong file .class thành các lệnh của máy, hệ điều hành tương ứng và thực thi chúng.

4.1. Class Loader Subsystem

Class Loader Subsystem chịu trách nhiện load, liên kết và khởi tạo file .class khí nó refer đến một class lần đầu tiên trong thời gian chạy (không phải thời gian biên dịch).

Loading các class sẽ được load bởi thành phần này. BootStrap class Loader , Extension class Loader , và Application class Loader là 3 trình nạp class sẽ giúp thực hiện được điều đó

  • Boot Strap ClassLoader : chịu trách nhiệm load các class từ classpath , đó là các file .jar . Ưu tiên cao nhất sẽ được trao cho trình nạp class này.
  • Extension ClassLoader : Chịu trách nhiệm load các class nằm trong thư mục jre\lib
  • Application ClassLoader : Chịu trách nhiệm load các class từ được cấu hình ở các đường dẫn (path) được đề cập trong biến môi trường.

Các trình nạp class bên trên tuân theo thuật toán phân cấp trong khi load các class .

Linking sẽ gồm thao tác:

  • Verify : Bytecode verifier (trình xác minh bytecode) sẽ kiểm tra xem byte code có được tạo ra phù hợp hay không. Nếu xác minh là không thành công, sẽ thông báo lỗi verify .
  • Prepare : Đối với tất cả các static variables memory sẽ được phân bổ và gán với các giá trị mặc định.
  • Resolve : Tất cả các tham chiếu bộ nhớ tượng trưng được thay thế bằng các tham chiếu ban đầu từ Method Area .

Cuối cùng là Initialization là giai đoạn cuối của Class Loading . Trong giai đoạn này các biến tĩnh (static variables) sẽ được gán với các giá trị ban đầu và static block sẽ được thực thi.

4.2. Runtime Data Area

Runtime Data Area được chia thành 5 thành phần chính:

  • Method area 
  • Heap area 
  • Stack area 
  • PC Registers 
  • Native Method stacks

4.3. Execution Engine (Công cụ thực thi)

Byte code sẽ được chỉ định cho Runtime Data Area , và sẽ được thực thi bới Execution Engine . Execution Engine đọc byte code từng mảng một.

  • Interpreter : Trình thông dịch dịch bytecode nhanh, nhưng thực thi chậm. Nhược điểm của trình thông dịch là khi một phương thức được gọi nhiều lần, mỗi lần cần một thông dịch mới.
  • JIT Compilier : Trình biên dịch JIT vô hiệu hóa nhược điểm của trình thông dịch (interpreter). Execution Engine sẽ sử dụng trợ giúp của trình thông dịch trong việc chuyển đổi byte code , nhưng khi thấy mã lặp lại , nó sẽ sử dụng trình biên dịch JIT. Nó biên dịch toàn bộ byte code và thay đổi nó thành mã gốc. Mã này sẽ được sử dụng khi các phương thức bị gọi lặp lại nhiều lần, điều này giúp cảu thiện hiệu năng của hệ thống.
  • Garbage Collector : Thu thập và loại bỏ các đối tượng được khởi tạo nhưng không sử dụng.