Lịch sử hình thành
Vào đầu những năm 1991, Dự án “Green” do James Gosling đừng đầu mong muốn phát triển được 1 kiến trúc chương trình có thể chạy trên nhiều nền tảng khác nhau. Lúc đầu, nhóm dự định dùng C++, nhưng C++ không thể đáp ứng được yêu cầu chạy đa nền tảng. Ví dụ: file Hello.exe được biên dịch trên hệ thống Windowns không thể chạy được trực tiếp trên môi trường Linux. Vào thời điểm đó, C++ rất phổ biến nhưng nó không thể chạy đa nền tảng nên bất đắc dĩ đàng phải từ bỏ
Vậy câu hỏi bây giờ đặt ra là làm thế nào để code chạy được trên nhiều nền tảng?
Trình thông dịch được nghĩ đến. Có nghĩa là mỗi khi một dòng code được chạy, mã máy sẽ được tạo và tiến hành thực thi. Ví dụ như Python và Ruby sử dụng trình thông dịch chỉ cần cài đặt một trình thông dịch trên mỗi hệ điều hành và mục tiêu đa nền tảng sẽ đạt được.
Nhưng trình thông dịch có một nhược điểm, đó là không thể tối ưu hóa như trình biên dịch để chương trình được chạy nhanh hơn. Vậy làm thế nào để khắc phục điều này?
Giải pháp được đưa ra là tiến hành kết hợp tình biên dịch và trình thông dịch
Trình biên dịch chịu trách nhiệm dịch mã Java thành mã byte và JVM chịu trách nhiệm chuyển đổi mã byte thành mã máy. Khi chuyển đổi, có thể thực hiện một số thao tác nén hoặc tối ưu hóa và hoàn thành nó thông qua JIT.
JVM Architecture
JVM bảo gồm 3 phần riêng biệt
Class Loader
Class Loader là phần cao nhất của JVM, được sử dụng để tải các lớp, các tệp .class. Nếu các tệp này không được tải thành công thì Runtime Data Area và Execution đều không làm gì cả. Class Loader chịu trách nghiệm tải các tệp bytecode vào bộ nhớ, chủ yếu trải qua 3 giai đoạn Loading -> Linking -> Initialization.
Runtime Data Area
Khu vực này được sử dụng để quản lý tài nguyên để thực thi bytecode, nếu không có tài nguyên nào còn thì một ngoại lệ OutOfMemoryError sẽ được đưa ra. JVM xác định vùng bộ nhớ được sử dụng trong quá trình chạy Java. Nói một cách đơn giản, data area lưu trữ thông tin và dự liệu bytecode trong quá trình thực thì chương trình. Trình GC cũng sẽ thực hiện thu gom các đối tượng cho runtime data area.
Execution Enginie
Được sử dụng để làm những việc cụ thể. “Máy ảo” và “máy vật lý” là hai khái niệm liên quan đến nhau. Cả hai đều có khả năng thực thi mã. Sự khác biệt là Execution của máy vật lý được xây dựng trực tiếp trên bộ xử lý, bộ đệm, tập lệnh và hệ điều hành, trong khi ở trên máy ảo chủ yếu được phần mềm triển khai, do đó, tập lệnh và thực thi có thể được tùy chỉnh mà không bị hạn chế bởi Điều kiện vật lý, có khả năng thực thi các định dạng tập lệnh được phần cứng hỗ trợ trực tiếp. Nhiệm vụ của Execution là biên dịch các bytecode thành các lệnh máy cục bộ trên nền tảng tương ứng. Nói một cách đơn giản, JVM hoạt động như một trình dịch từ ngôn ngữ cấp cao sang ngôn ngữ máy
Interpreter: đọc bytecode và sau đó thực hiện các hướng dẫn. Do nó diễn giải và thực thi từng dòng lệnh nên nó có thể diễn giải mã byte nhanh chóng, nhưng việc thực thi sẽ chậm hơn. JIT Compiler: Thực thi theo các phương thức diễn giải và thực thi theo thời gian, trình biên dịch đúng lúc sẽ biên dịch có chọn lọc một số mã thành mã cục bộ. Việc thực thi mã cục bộ nhanh hơn nhiều so với việc diễn giải từng mã một vì mã cục bộ được lưu trọng bộ đệm Garbage Collector: được sử dụng để thu thập các đối tượng rác trong bộ nhớ Heap
Tổng kết:
Nhìn chung, JVM là một môi trường trong đó các chương trình Java được thực thi, giúp che giấu đi sự phức tạp của hệ điều hành và phần cứng cơ bản, đồng thời cung cấp một nền tảng vận hành thống nhất, ổn định và an toàn.
Chúng ta ném tệp bytecode của mã nguồn Java vào đó và nó có thể được thực thi trong JVM. Cho dù được biên dịch trong môi trường Windows, Linux hay MacOs, nó vẫn có thể chạy mà không quan tâm đến sự khác biệt trong hệ điều hành.