Máy ảo và CLR của Java


140

Là một loại tiếp theo cho câu hỏi được gọi là Sự khác biệt giữa mã MSIL và mã byte Java? , sự khác biệt hoặc tương đồng (chính) trong cách thức hoạt động của Máy ảo Java so với cách thức.Nền tảng NET Thời gian chạy ngôn ngữ chung (CLR) hoạt động?

Ngoài ra, là .Nền tảng NET CLR một "máy ảo" hoặc nó không có các thuộc tính của một máy ảo?


Chà, nếu bạn đang so sánh thích và thích, bạn nên đặt lại câu hỏi là sự khác biệt giữa VM và CLR (Thời gian chạy ngôn ngữ chung), là tương tự trực tiếp với VM.
cletus

Câu trả lời:


278

Có rất nhiều điểm tương đồng giữa cả hai triển khai (và theo tôi: có, cả hai đều là "máy ảo").

Đối với một điều, cả hai đều là VM dựa trên ngăn xếp, không có khái niệm "thanh ghi" như chúng ta thường thấy trong một CPU hiện đại như x86 hoặc PowerPC. Việc đánh giá tất cả các biểu thức ((1 + 1) / 2) được thực hiện bằng cách đẩy các toán hạng lên "ngăn xếp" và sau đó bật các toán hạng đó ra khỏi ngăn xếp bất cứ khi nào một lệnh (thêm, chia, v.v.) cần tiêu thụ các toán hạng đó. Mỗi hướng dẫn đẩy kết quả của nó trở lại vào ngăn xếp.

Đây là một cách thuận tiện để triển khai máy ảo, vì hầu hết mọi CPU trên thế giới đều có một ngăn xếp, nhưng số lượng thanh ghi thường khác nhau (và một số thanh ghi là mục đích đặc biệt và mỗi lệnh đều mong đợi toán hạng của nó trong các thanh ghi khác nhau, v.v. ).

Vì vậy, nếu bạn định tạo mô hình một cỗ máy trừu tượng, một mô hình hoàn toàn dựa trên ngăn xếp là một cách khá hay.

Tất nhiên, máy thật không hoạt động theo cách đó. Vì vậy, trình biên dịch JIT chịu trách nhiệm thực hiện "đăng ký" các hoạt động của mã byte, về cơ bản lập lịch trình các thanh ghi CPU thực tế để chứa các toán hạng và kết quả bất cứ khi nào có thể.

Vì vậy, tôi nghĩ đó là một trong những điểm tương đồng lớn nhất giữa CLR và JVM.

Còn về sự khác biệt ...

Một sự khác biệt thú vị giữa hai triển khai là CLR bao gồm các hướng dẫn để tạo các loại chung và sau đó để áp dụng các chuyên ngành tham số cho các loại đó. Vì vậy, trong thời gian chạy, CLR coi Danh sách <int> là một loại hoàn toàn khác với Danh sách <Chuỗi>.

Trong các trang bìa, nó sử dụng cùng một MSIL cho tất cả các chuyên môn kiểu tham chiếu (do đó, Danh sách <Chuỗi> sử dụng cùng cách thực hiện với Danh sách <Đối tượng>, với các kiểu phôi khác nhau ở ranh giới API), nhưng mỗi loại sử dụng loại giá trị triển khai duy nhất của riêng nó (Danh sách <int> tạo mã hoàn toàn khác với Danh sách <double>).

Trong Java, các kiểu chung hoàn toàn là một thủ thuật biên dịch. JVM không có khái niệm về các lớp nào có đối số kiểu và nó không thể thực hiện các chuyên môn tham số khi chạy.

Từ góc độ thực tế, điều đó có nghĩa là bạn không thể quá tải các phương thức Java trên các kiểu chung. Bạn không thể có hai phương thức khác nhau, có cùng tên, chỉ khác nhau về việc chúng có chấp nhận Danh sách <Chuỗi> hay Danh sách <Ngày>. Tất nhiên, vì CLR biết về các loại tham số, nên không có phương thức xử lý vấn đề nào bị quá tải đối với các chuyên ngành loại chung.

Trên cơ sở hàng ngày, đó là sự khác biệt mà tôi nhận thấy nhiều nhất giữa CLR và JVM.

Sự khác biệt quan trọng khác bao gồm:

  • CLR đã đóng cửa (được triển khai dưới dạng đại biểu C #). JVM chỉ hỗ trợ các bao đóng kể từ Java 8.

  • CLR có coroutines (được triển khai với từ khóa C #'ield '). JVM thì không.

  • CLR cho phép mã người dùng xác định các loại giá trị mới (structs), trong khi JVM cung cấp một tập hợp cố định các loại giá trị (byte, short, int, long, float, double, char, boolean) và chỉ cho phép người dùng xác định tham chiếu mới- các loại (lớp).

  • CLR cung cấp hỗ trợ cho việc khai báo và thao tác con trỏ. Điều này đặc biệt thú vị bởi vì cả JVM và CLR đều sử dụng các triển khai thu gom rác nén thế hệ nghiêm ngặt như là chiến lược quản lý bộ nhớ của họ. Trong các trường hợp thông thường, một GC nén chặt có một thời gian thực sự khó khăn với các con trỏ, bởi vì khi bạn di chuyển một giá trị từ vị trí bộ nhớ này sang vị trí bộ nhớ khác, tất cả các con trỏ (và con trỏ đến con trỏ) đều không hợp lệ. Nhưng CLR cung cấp một cơ chế "ghim" để các nhà phát triển có thể khai báo một khối mã trong đó CLR không được phép di chuyển một số con trỏ nhất định. Nó rất tiện lợi.

  • Đơn vị mã lớn nhất trong JVM là 'gói' được chứng minh bằng từ khóa 'được bảo vệ' hoặc được cho là JAR (tức là Java ARchive) được chứng minh bằng cách có thể chỉ định một jar trong đường dẫn lớp và được xử lý như một thư mục mã. Trong CLR, các lớp được tổng hợp thành 'cụm' và CLR cung cấp logic để suy luận và thao tác các cụm (được tải vào "AppDomains", cung cấp các hộp cát cấp ứng dụng phụ để cấp phát bộ nhớ và thực thi mã).

  • Định dạng mã byte CLR (bao gồm các lệnh MSIL và siêu dữ liệu) có ít loại lệnh hơn JVM. Trong JVM, mọi hoạt động duy nhất (thêm hai giá trị int, thêm hai giá trị float, v.v.) có hướng dẫn riêng của nó. Trong CLR, tất cả các lệnh MSIL là đa hình (thêm hai giá trị) và trình biên dịch JIT chịu trách nhiệm xác định các loại toán hạng và tạo mã máy thích hợp. Tôi không biết đó là chiến lược tốt nhất, mặc dù. Cả hai đều có sự đánh đổi. Trình biên dịch JIT HotSpot, đối với JVM, có thể sử dụng cơ chế tạo mã đơn giản hơn (không cần xác định các loại toán hạng, vì chúng đã được mã hóa trong hướng dẫn), nhưng điều đó có nghĩa là nó cần định dạng mã byte phức tạp hơn, với nhiều loại hướng dẫn hơn.

Tôi đã sử dụng Java (và ngưỡng mộ JVM) khoảng mười năm nay.

Nhưng, theo tôi, CLR hiện là sự triển khai vượt trội, gần như trên mọi phương diện.


73
Đóng cửa và máy phát điện được thực hiện ở cấp độ ngôn ngữ và được biểu diễn đơn giản dưới dạng các lớp ở cấp độ CLR.
Curt Hagenlocher

2
Điều gì về sự khác biệt trong cách họ xử lý đống? CLR phụ thuộc nhiều hơn vào hệ điều hành / máy chủ lưu trữ trong khi JVM quản lý bộ nhớ heap hoàn toàn ít nhiều.
Kelly S. Pháp

6
Một sự khác biệt quan trọng là sự tương phản giữa biên dịch đúng lúc (CLR) và tối ưu hóa thích ứng trong JVM (Oracle / Sun).
Edwin Dalorzo

1
Các khe biến cục bộ của Java hoạt động giống như các thanh ghi. Nhưng dù sao thì đó cũng là tất cả vì JIT biến các vị trí cục bộ và ngăn xếp thành các thanh ghi thực.
Antimon

1
@kuhajeyan đó là vì khi CLR được giới thiệu, JVM đã được 10 tuổi. đó là một thời gian dài trong CNTT. Khi JVM xuất hiện vào năm 1993, không có đối thủ nặng ký, đối với CLR (2003) đã có một JVM trưởng thành và vững chắc với chỗ đứng vững chắc trong ngành.
Đồng nghiệp đơn giản

25

Câu hỏi đầu tiên của bạn là so sánh JVM với .NET Framework - Tôi giả sử bạn thực sự muốn so sánh với CLR. Nếu vậy, tôi nghĩ bạn có thể viết một cuốn sách nhỏ về điều này ( EDIT: có vẻ như Benji đã có :-)

Một điểm khác biệt quan trọng là CLR được thiết kế theo kiến ​​trúc trung lập ngôn ngữ, không giống như JVM.

Một sự khác biệt quan trọng khác là CLR được thiết kế đặc biệt để cho phép mức độ tương tác cao với mã gốc. Điều này có nghĩa là CLR phải quản lý độ tin cậy và bảo mật khi bộ nhớ riêng được truy cập và sửa đổi, đồng thời quản lý việc sắp xếp giữa các cấu trúc dữ liệu dựa trên CLR và cấu trúc dữ liệu gốc.

Để trả lời câu hỏi thứ hai của bạn, thuật ngữ máy ảo ảo trực tuyến là một thuật ngữ cũ hơn từ thế giới phần cứng (ví dụ như ảo hóa 360 của IBM vào những năm 1960) có nghĩa là mô phỏng phần mềm / phần cứng của máy bên dưới để thực hiện cùng một loại những thứ mà VMWare làm.

CLR thường được gọi là "công cụ thực thi". Trong bối cảnh này, đó là việc triển khai Máy IL trên đầu x86. Đây cũng là những gì JVM làm, mặc dù bạn có thể lập luận rằng có một sự khác biệt quan trọng giữa các mã byte đa hình của CLR và các mã byte được gõ của JVM.

Vì vậy, câu trả lời pedantic cho câu hỏi thứ hai của bạn là "không". Nhưng nó thực sự phụ thuộc vào cách bạn xác định hai thuật ngữ này.

EDIT: Một điểm khác biệt nữa giữa JVM và CLR là JVM (phiên bản 6) rất miễn cưỡng giải phóng bộ nhớ được phân bổ trở lại hệ điều hành, ngay cả khi có thể.

Ví dụ, giả sử rằng một quy trình JVM khởi động và phân bổ 25 MB bộ nhớ từ hệ điều hành ban đầu. Mã ứng dụng sau đó thử phân bổ yêu cầu thêm 50 MB. JVM sẽ phân bổ thêm 50 MB từ hệ điều hành. Khi mã ứng dụng đã ngừng sử dụng bộ nhớ đó, nó sẽ được thu gom rác và kích thước heap JVM sẽ giảm. Tuy nhiên, JVM sẽ chỉ giải phóng bộ nhớ hệ điều hành được phân bổ trong các trường hợp cụ thể nhất định . Mặt khác, trong phần còn lại của quá trình mà bộ nhớ sẽ được phân bổ.

CLR, mặt khác, giải phóng bộ nhớ được phân bổ trở lại hệ điều hành nếu không còn cần thiết nữa. Trong ví dụ trên, CLR sẽ giải phóng bộ nhớ khi heap giảm.


2
Điều này tuyệt đối không đúng khi JVM sẽ không giải phóng bộ nhớ. Xem câu trả lời của tôi cho câu hỏi này để biết bằng chứng: stackoverflow.com/questions/366658/ Kẻ
Michael Borgwardt

Tôi đã thấy bộ nhớ trả về JVM trở lại Windows.
Steve Kuo

Tôi đã thay đổi câu trả lời của mình để nói rằng JVM 6 rất miễn cưỡng giải phóng bộ nhớ, với các liên kết đến câu trả lời của Ran và Michael. Tôi chưa bao giờ thấy hành vi này với JVM 5, vì vậy có lẽ phiên bản đó thậm chí còn miễn cưỡng hơn.
HTTP 410

Bạn có thể trình bày cách JVM chủ động quản lý vùng heap trong khi CLR phụ thuộc vào tiến trình cha không? Ví dụ cụ thể mà tôi sử dụng là JVM có thời gian chạy args cho kích thước heap tối đa trong khi môi trường CLR mặc định thì không. Mặc dù đúng là ứng dụng CLR được lưu trữ trong IIS có thể định cấu hình IIS để giới hạn bộ nhớ, điều đó có nghĩa là bao gồm IIS trong định nghĩa của máy ảo.
Kelly S. Pháp

@Steve Kuo, vâng tôi cũng đã thấy điều đó. thường từ 5 giờ chiều đến 6 giờ chiều.
Đồng nghiệp đơn giản

11

CLR và JVM đều là máy ảo.

.NET Framework và Môi trường chạy thi hành Java là gói các VM tương ứng và các thư viện của chúng. Không có thư viện, VM rất vô dụng.


11

Cụ thể hơn về sự khác biệt có thể được tìm thấy từ các nguồn học thuật và tư nhân khác nhau. Một khi ví dụ tốt là lựa chọn thiết kế CLR .

Một số ví dụ cụ thể bao gồm:

  • Một số opperand cấp thấp được gõ như "thêm hai int" trong đó CLR sử dụng toán hạng đa hình. (tức là fadd / iadd / ladd vs chỉ cần thêm)
  • Hiện tại, JVM thực hiện cấu hình và tối ưu hóa thời gian chạy nhanh hơn (ví dụ Hotspot). CLR hiện thực hiện tối ưu hóa JIT, nhưng không tối ưu hóa thời gian chạy (tức là thay thế mã trong khi bạn đang chạy).
  • CLR không có các phương thức ảo nội tuyến, JVM không ...
  • Hỗ trợ cho các loại giá trị trong CLR không chỉ là "nguyên thủy".

-11

Nó không phải là một máy ảo, khung .net biên dịch các cụm thành nhị phân nguyên gốc tại lần chạy đầu tiên:

Trong điện toán, biên dịch đúng lúc (JIT), còn được gọi là dịch động, là một kỹ thuật để cải thiện hiệu năng thời gian chạy của một chương trình máy tính. JIT xây dựng dựa trên hai ý tưởng trước đó trong môi trường thời gian chạy: biên dịch mã byte và biên dịch động. Nó chuyển đổi mã trong thời gian chạy trước khi thực hiện nó một cách tự nhiên, ví dụ mã byte thành mã máy gốc. Sự cải thiện hiệu suất đối với các trình thông dịch bắt nguồn từ việc lưu trữ kết quả của việc dịch các khối mã và không chỉ đơn giản là đánh giá lại từng dòng hoặc toán hạng mỗi khi nó được đáp ứng (xem Ngôn ngữ được giải thích). Nó cũng có lợi thế so với việc biên dịch mã tĩnh tại thời điểm phát triển, vì nó có thể biên dịch lại mã nếu điều này được coi là thuận lợi và có thể thực thi các bảo đảm an ninh.

Một số môi trường thời gian chạy hiện đại, như .NET Framework của Microsoft, hầu hết các triển khai Java và gần đây nhất là Actioncript 3, dựa vào trình biên dịch JIT để thực thi mã tốc độ cao.

Nguồn: http://en.wikipedia.org/wiki/Just-in-time_compilation

Thêm .NET framework chứa một máy ảo, giống như Java.


10
Chỉ vì máy ảo sử dụng JIT để tối ưu hóa hiệu suất không có nghĩa là nó không phải là máy ảo nữa. Khi lập trình viên biên dịch, anh ta biên dịch vào máy ảo, để lại việc thực hiện để thực hiện việc thực thi tuy nhiên nó thấy phù hợp
Allain Lalonde
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.