Tại sao máy ảo cần phải là máy xếp chồng kiểu máy tính hay máy tính đăng ký của máy tính, v.v.


48

(Đây là một câu hỏi cực kỳ mới mẻ).

Tôi đã nghiên cứu một chút về Máy ảo.

Hóa ra rất nhiều trong số chúng được thiết kế rất giống với máy tính vật lý hoặc lý thuyết.

Tôi đọc rằng JVM chẳng hạn, là một 'máy stack'. Điều đó có nghĩa là gì (và sửa cho tôi nếu tôi sai) là nó lưu trữ tất cả 'bộ nhớ tạm thời' trên một ngăn xếp và thực hiện các thao tác trên ngăn xếp này cho tất cả các mã của nó.

Ví dụ: mã nguồn 2 + 3sẽ được dịch sang mã byte tương tự như:

push 2
push 3
add

Câu hỏi của tôi là:

Các JVM có thể được viết bằng C / C ++ và như vậy. Nếu vậy, tại sao JVM không thực thi mã C sau: 2 + 3..? Ý tôi là, tại sao nó cần một ngăn xếp, hoặc trong các 'thanh ghi' VM khác - như trong một máy tính vật lý?

CPU vật lý cơ bản đảm nhận tất cả những điều này. Tại sao các nhà văn VM không thực hiện đơn giản mã byte được giải thích bằng các hướng dẫn 'thông thường' trong ngôn ngữ mà VM được lập trình?

Tại sao máy ảo cần mô phỏng phần cứng, khi phần cứng thực tế đã làm điều này cho chúng ta?

Một lần nữa, những câu hỏi rất mới. Cảm ơn bạn đã giúp đỡ


5
Bạn đã xem xét những gì máy ảo không dựa trên?

5
@MichaelT Ý bạn là máy vật lý?
Manila Cohn

Tất nhiên, hầu hết các máy ảo Javascript không xếp máy hoặc đăng ký máy - V8 / IonMonkey / Chakra / v.v. là máy ảo triển khai Javascript. "VM" chỉ là trình thông dịch hoặc trình biên dịch JIT có thể thực hiện bất kỳ ngôn ngữ nào mà nhà thiết kế mong muốn.
Billy ONeal

@BillyONeal Vì vậy, ví dụ: nếu tôi đang viết VM cho một số ngôn ngữ và tôi đang viết nó bằng C: VM phân tích cú pháp dòng mã 'in "hi" và thực thi printf("hi");: đây có được coi là VM không? Nó không có 'ngăn xếp' hoặc 'thanh ghi' và bất cứ thứ gì.
Manila Cohn

@Prog: Đúng, đúng vậy.
Billy ONeal

Câu trả lời:


51

Một cỗ máy, ảo hay không, cần một mô hình tính toán mô tả cách tính toán được thực hiện trên nó. Theo định nghĩa, ngay khi tính toán, nó thực hiện một số mô hình tính toán. Câu hỏi sau đó là: Chúng ta nên chọn mô hình nào cho VM của mình? Máy vật lý bị hạn chế bởi những gì có thể được thực hiện hiệu quả và hiệu quả trong phần cứng. Nhưng, như bạn lưu ý, các máy ảo không có các ràng buộc như vậy, chúng được xác định trong phần mềm bằng các ngôn ngữ cấp cao tùy ý.

Trên thực tế, có những máy ảo có mức độ cao như bạn mô tả. Chúng được gọi là ngôn ngữ lập trình . Ví dụ, tiêu chuẩn C dành phần lớn các trang của nó để xác định mô hình cho cái gọi là "máy trừu tượng C" mô tả cách các chương trình C hoạt động và bằng cách mở rộng (quy tắc as-if) cách trình biên dịch C (hoặc trình thông dịch) tuân thủ) nên cư xử.

Tất nhiên, chúng ta thường không gọi đó là một máy ảo. Một VM thường có nghĩa là một cái gì đó ở cấp độ thấp hơn, gần với phần cứng hơn, không có ý định được lập trình trực tiếp, được thiết kế để được thực thi hiệu quả. Xu hướng lựa chọn này có nghĩa là một cái gì đó chấp nhận mã có thể tổng hợp cấp cao (như những gì bạn mô tả) sẽ không được coi là VM đang thực thi mã cấp cao.

Nhưng để đi đến điểm chính, đây là một số lý do để tạo một VM (như trong, một cái gì đó được nhắm mục tiêu bởi trình biên dịch mã byte) dựa trên đăng ký hoặc tương tự. Máy xếp và đăng ký cực kỳ đơn giản. Có một chuỗi các hướng dẫn, một số trạng thái và ngữ nghĩa cho mỗi hướng dẫn (Trạng thái chức năng -> Trạng thái). Không giảm cây phức tạp, không có quyền ưu tiên của nhà điều hành. Phân tích cú pháp, phân tích và thực hiện nó rất đơn giản, vì đó là ngôn ngữ tối thiểu (đường cú pháp được biên dịch) và được thiết kế để đọc bằng máy chứ không phải đọc bằng con người.

Ngược lại, phân tích cú pháp ngay cả những ngôn ngữ giống như C đơn giản nhất cũng khá khó khăn và việc thực thi nó đòi hỏi các phân tích không cục bộ như kiểm tra và truyền bá các loại, giải quyết tình trạng quá tải, duy trì bảng ký hiệu, giải quyết định danh chuỗi , biến văn bản tuyến tính thành AST theo hướng ưu tiên , v.v. Nó được xây dựng trên các khái niệm đến với con người một cách tự nhiên nhưng phải được chế tạo một cách tỉ mỉ bằng máy móc.

Ví dụ, mã byte JVM được phát ra bởi javac. Nó hầu như không bao giờ cần phải đọc hoặc viết bởi con người, vì vậy việc đưa nó vào tiêu dùng bằng máy móc là điều tự nhiên. Nếu bạn được tối ưu hóa nó đối với con người, JVM sẽ chỉ trên mỗi khởi động đọc mã, phân tích nó, phân tích là, và sau đó chuyển đổi nó thành một đại diện trung gian giống như một đơn giản hóa mô hình máy như thế nào . Cũng có thể cắt bỏ người đàn ông giữa.


Vì vậy, những gì bạn đang nói là việc biên dịch mọi thứ theo hướng dẫn trên ngăn xếp (nghĩa System.out.println("hi");là được biên dịch theo một số lệnh trên ngăn xếp, int a = 7được biên dịch thành một lệnh trên ngăn xếp, v.v.) làm cho việc thực hiện chương trình đơn giản và hiệu quả hơn?
Manila Cohn

2
@Prog Về cơ bản, vâng. Nhưng không chỉ thực hiện, cũng phân tích. Tất cả mọi thứ được thực hiện theo chương trình.

Tuy nhiên, tôi không hiểu tại sao 2 + 3được biên dịch push 2 push 3 add. Các addbước cuối cùng được thực hiện bởi các JVM nào bằng cách chạy mã C 2 + 3. Không có cách nào khác để các lập trình viên của JVM làm điều này. Tại sao không biên dịch nó thành 2 + 3và để JVM chỉ thực thi mã C 2 + 3(giả sử nó được viết bằng C) ngay lập tức?
Manila Cohn

@Prog Tác giả JVM không thể chỉ viết 2 + 3mã nguồn JVM vì JVM phải làm việc với bất kỳ chương trình nào thực hiện bất kỳ hoạt động nào theo bất kỳ thứ tự nào. Xây dựng mã nguồn C và trì hoãn triển khai C chỉ đẩy vấn đề tương tự vào triển khai C (và không thể thực hiện dễ dàng, nói gì đến hiệu quả). Phải có một số cấu trúc dữ liệu mô tả chương trình, để nó có thể được giải thích và biên dịch JIT, và "mã nguồn có thể đọc được của con người" là một lựa chọn khủng khiếp về cấu trúc dữ liệu vì những lý do đã nêu ở trên.

7
@Prog Bạn có vẻ quá tập trung vào trường hợp cụ thể của 2 + 3. Còn về a + b? Sau đó, các giá trị để thêm không đến i.argument{1,2}, chúng được tải từ các biến cục bộ. Thế còn frobnicate(x[i]) + (Foo.bar() * 2)? Sử dụng thiết kế này, chỉ có một addthao tác (cho int) và nó hoạt động độc lập với cách tính toán các phần bổ sung. Thêm vào đó, một lệnh có thêm chỉ số nguyên literals sẽ là vô nghĩa: kết quả của nó có thể chỉ cũng được tính toán trước (tức là thay vì add(2,3)nó phải được push(5)).

20

Câu trả lời này tập trung vào JVM, nhưng thực tế nó áp dụng cho bất kỳ VM nào.

Tại sao máy ảo cần mô phỏng phần cứng, khi phần cứng thực tế đã làm điều này cho chúng ta?

Chúng không, nhưng nó làm cho VM đơn giản và dễ mang hơn nhiều: Một VM mô phỏng phần cứng có thể sử dụng cùng một mô hình tính toán hơn bất kỳ CPU phần cứng nào.

JVM nói riêng được xây dựng với tính di động, trên thực tế, nó được xây dựng để nó thậm chí có thể được triển khai trong phần cứng (ngày nay có thể khó tin, nhưng nguồn gốc của Java là trong thế giới nhúng - cụ thể là bộ điều khiển cho truyền hình tương tác ).

Nếu bạn có một mục tiêu như thế này, điều mong muốn là VM hoạt động càng gần một máy vật lý càng tốt, bởi vì việc dịch sang mã máy thực tế trở nên dễ dàng hơn và do đó nhanh hơn. Về lý thuyết, khi bạn có opcodes của VM, tất cả những gì bạn phải làm là dịch sang opcodes của CPU mà chương trình thực sự chạy. Trong thực tế nó không chính xác đơn giản.

Ý tôi là, tại sao nó cần một ngăn xếp, hoặc trong các 'thanh ghi' VM khác - như trong một máy tính vật lý?

Sử dụng một mô hình máy ảo dựa trên ngăn xếp có lợi thế là nó có thể dễ dàng được chuyển sang cả máy đăng ký và máy stack, trong khi điều ngược lại không nhất thiết là đúng. Một VM dựa trên thanh ghi sẽ cần phải đưa ra các giả định về số lượng thanh ghi, kích thước của các thanh ghi, v.v ... Với một máy stack, không cần các giả định như vậy.

CPU vật lý cơ bản đảm nhận tất cả những điều này. Tại sao các nhà văn VM không thực hiện đơn giản mã byte được giải thích bằng các hướng dẫn 'thông thường' trong ngôn ngữ mà VM được lập trình?

Chà, đó là những gì các máy ảo như vậy làm, chúng diễn giải mã byte. Ngay cả JVM cũng thực sự làm điều đó, ít nhất là trước khi JIT (chỉ trong thời gian) khởi động: nó diễn giải mã byte và thực thi các câu lệnh bằng ngôn ngữ mà JVM được viết bằng (thường là C hoặc C ++, nhưng thậm chí còn có một chữ viết trong JavaScript, Doppio ). Tuy nhiên, lưu ý rằng ngay cả các câu lệnh như vậy đã được dịch sang mã máy bởi trình biên dịch và thực sự trông rất giống với trình biên dịch Java tạo ra - cụ thể là, chúng sử dụng các thanh ghi và ngăn xếp để thực hiện công việc của chúng. Lưu ý rằng việc sử dụng các ngôn ngữ "được giải thích" và "được biên dịch" trở nên hơi mờ vào thời điểm này.


Tất nhiên, bất cứ điều gì có thể được thực hiện trong phần mềm đều có thể được thực hiện trong phần cứng. Ngoài ra, JVM hiện tại (hotspot) là một trình biên dịch JIT - nó không thực thi các câu lệnh bằng ngôn ngữ mà JVM đã được viết. Nếu có, Java sẽ hoạt động khủng khiếp và sẽ không còn là một nền tảng khả thi như ngày nay. . (Địa ngục, hầu hết các triển khai Javascript sẽ nhanh hơn)
Billy ONeal

2
@BillyONeal "Thay vì biên dịch theo phương thức, ngay lúc đó, Java HotSpot VM ngay lập tức chạy chương trình bằng trình thông dịch và phân tích mã khi nó chạy để phát hiện các điểm nóng quan trọng trong chương trình. Sau đó, nó tập trung sự chú ý của một Trình tối ưu hóa mã gốc toàn cầu trên các điểm nóng. "được trích dẫn từ oracle.com/technetwork/java/whitepaper-135217.html#2 , phần" Phát hiện điểm nóng "
miraculixx

Đúng. "Trình tối ưu hóa mã gốc" == Biên dịch JIT. Có một giai đoạn thông dịch cho mã dường như không "nóng" để tránh JITing những thứ hiếm khi được sử dụng. Nhưng điều đó không có nghĩa là không có JITing nào được thực hiện cả.
Billy ONeal

Cảm ơn đã trả lời. Những gì tôi thu thập được từ câu trả lời của bạn là lý do để mô phỏng phần cứng trong VM (còn gọi là 'ngăn xếp' hoặc 'thanh ghi', v.v.) là vì nó giúp dễ dàng biên dịch mã byte hoặc mã nguồn thành mã máy thực tế của một CPU vật lý. Tuy nhiên, ngoài điều đó - có bất cứ điều gì để đạt được từ việc mô phỏng phần cứng trong máy ảo không? Tôi vẫn không hiểu tại sao một người nào đó thiết kế VM sẽ nghĩ về 'máy xếp' hay 'máy đăng ký', v.v. trong khi thực tế chúng ta đang nói về phần mềm. Tui bỏ lỡ điều gì vậy?
Manila Cohn

@Prog Ok, bạn có ngôn ngữ lập trình, nói X. Bạn sẽ chạy các chương trình của nó như thế nào? Bạn có thể giải thích nguồn hoặc biên dịch nó thành mã máy hoặc biên dịch nó thành một số mã trung gian. Bây giờ bạn có một ngôn ngữ lập trình khác, Y và muốn triển khai nó bằng X. Nếu cả hai triển khai đều là trình thông dịch, bạn sẽ có trình thông dịch của Y chạy trên trình thông dịch của X và điều này sẽ rất chậm.
18446744073709551615

11

Tại sao máy ảo cần phải là máy xếp chồng kiểu máy tính hay máy tính đăng ký của máy tính, v.v.

Họ không. Nếu bạn cần một máy ảo, nó có thể là bất cứ thứ gì.

Các máy ảo hiện có đã xuất hiện dưới dạng giải pháp cho các tình huống như: Một ý tưởng thực sự xuất sắc đã xuất hiện trong đầu tôi, tôi đã phát minh ra một ngôn ngữ lập trình mới! Nhưng tôi phải tạo mã. (Thật là một nhiệm vụ nhàm chán!) Nhưng tôi không muốn tạo mã i8086 vì nó xấu và tôi không muốn tạo mã 68k vì mọi người khác đang sử dụng Intel. Cũng có VAX, nhưng tôi không có VAX, cả máy tính lẫn sách VAX. Do đó, tôi sẽ tạo mã cho một số bộ xử lý không tồn tại về mặt vật lý và triển khai bộ xử lý đó trong phần mềm. Thông số kỹ thuật của VM đó sẽ tạo ra một chương trong luận án của tôi. Về lý thuyết, có thể biên dịch nó thành mã riêng của bất kỳ bộ xử lý nào, nhưng đó không phải là tôi.

Mặt khác, ký hiệu như "2 + 3" có thể sẽ không được sử dụng bởi các máy ảo trong tương lai gần bởi vì nó ngụ ý thực hiện nhiều biến đổi trước khi một cái gì đó có thể được thực thi.


Cảm ơn đã trả lời. Vì vậy, những gì tôi thu thập được từ câu trả lời của bạn, đó là động lực để thiết kế một VM mô phỏng CPU vật lý là bởi vì nó giúp dễ dàng thực hiện các trình biên dịch biên dịch thành mã máy thực tế. Nhưng ngoài điều đó - có bất kỳ lợi thế nào khi thiết kế VM theo 'máy xếp' hay 'máy đăng ký', v.v. không?
Manila Cohn

1
Các thanh ghi yêu cầu các thuật toán phân bổ đăng ký, cần cả lý thuyết và gỡ lỗi. Một máy stack (đặc biệt là một toán hạng 0) chỉ có thể đặt dữ liệu lên ngăn xếp. OTOH, phần cứng thường thực hiện một số lượng hạn chế các thanh ghi hơn là một ngăn xếp có kích thước thay đổi. Vì vậy, ngăn xếp dễ dàng hơn cho phần mềm, thanh ghi dễ dàng hơn cho phần cứng và do đó có thể nhanh hơn một chút.
18446744073709551615

-2

Để trả lời câu hỏi thực tế đã được hỏi. Thuật ngữ "MÁY ảo" có nghĩa là TẤT CẢ phần mềm / phần cứng được mô phỏng / mô phỏng. Nếu bạn sử dụng phần mềm / phần cứng cơ bản để thực hiện các hướng dẫn thì bạn không có VM, bạn có trình biên dịch / trình thông dịch.


Đây chỉ là ý kiến ​​của bạn hoặc bạn có thể sao lưu nó bằng cách nào đó?
gnat

@Kyrelel đó là không đúng sự thật. Phần cứng "TẤT CẢ" được mô phỏng trong VM "hệ thống" hoặc "đầy đủ". Không phải tất cả các máy ảo đều đầy đủ. Ví dụ, lớp BSD VM được đặt tên là "máy ảo", mặc dù phần cứng không được mô phỏng ở đó.
Lấy

Tôi không nghĩ câu hỏi này nhất thiết là về thuật ngữ, mà là tại sao các máy ảo thực hiện chức năng dường như đã được xử lý bởi phần cứng thực tế
Ryan
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.