2010-10-17 34 views
16

Trong số các ngôn ngữ hướng đối tượng tôi biết, khá nhiều tất cả, nhưng C++ và Objective-C biên dịch thành bytecode chạy trên một số loại máy ảo. Tại sao có quá nhiều ngôn ngữ khác nhau được giải quyết khi biên dịch sang bytecode, trái ngược với mã máy? Liệu có thể có một ngôn ngữ OOP được quản lý bằng bộ nhớ cao được biên dịch thành mã máy không?Tại sao hầu như tất cả các ngôn ngữ OO được biên dịch sang bytecode?

Chỉnh sửa: Tôi biết rằng hỗ trợ đa nền tảng thường được nâng cao như một lợi thế của phương pháp này. Tuy nhiên, nó hoàn toàn có thể biên dịch tự nhiên trên nhiều nền tảng, mà không cần tạo một trình biên dịch mới cho mỗi nền tảng. Người ta có thể, ví dụ, phát ra mã C và sau đó biên dịch với GCC.

+0

Tôi đoán điều này là do chúng được thiết kế cho hiệu quả, và bytecode/VM hầu như luôn đi kèm với một sự cân bằng hiệu suất.Tuy nhiên, lưu ý rằng cả C++ và Objective-C biên dịch thành bytecode LLVM mà sau đó có thể được chuyển đổi thành mã gốc. –

+1

@Diego: Trong * một số * triển khai. 'gcc' không biên dịch thành LLVM, và tôi chắc rằng Visual Studio cũng vậy. – sepp2k

+0

@ sepp2k: Tôi không hiểu ý bạn là gì với "gcc không biên dịch thành LLVM". LLVM có thể biên dịch C, C++ và Objective-C thành bytecode và thành mã gốc sau đó (tất nhiên, trong một số nền tảng) một mình. –

Trả lời

13

Không có lý do nào trong thực tế, đây là một loại trùng hợp ngẫu nhiên. OOP bây giờ là khái niệm hàng đầu trong lập trình "lớn", và các máy ảo như thế.

Cũng lưu ý, rằng có 2 phần riêng biệt của máy ảo truyền thống - garbage collectorbytecode interpreter/JIT-biên dịch, và các bộ phận này có thể tồn tại độc lập. Ví dụ, việc triển khai Common Lisp được gọi là SBCL biên dịch chương trình thành một mã nguồn gốc, nhưng tại thời gian chạy rất nhiều sử dụng bộ sưu tập rác.

+3

Tôi nghĩ rằng bạn có nghĩa là "nặng nề" thay vì "khó" trong câu cuối cùng của bạn. – sepp2k

+0

vâng, sửa chữa nó, cảm ơn bạn. – ffriend

+1

+1 để cắm SBCL;) – tobyodavies

12

Điều này được thực hiện để cho phép trình biên dịch VM hoặc JIT có cơ hội biên dịch mã theo yêu cầu tối ưu cho kiến ​​trúc mà mã được thực thi. Ngoài ra, nó cho phép bytecode đa nền tảng được tạo ra một lần và sau đó được thực thi trên nhiều kiến ​​trúc phần cứng. Điều này cho phép tối ưu hóa phần cứng cụ thể được đặt vào mã được biên dịch.

Vì mã byte không bị giới hạn đối với kiến ​​trúc vi mô, nó có thể nhỏ hơn mã máy. Các lệnh phức tạp có thể được biểu diễn so với các lệnh nguyên thủy có sẵn trong các CPU ngày hiện đại, vì các ràng buộc trong việc thiết kế các lệnh CPU rất khác với các ràng buộc trong việc thiết kế kiến ​​trúc bytecode.

Sau đó, có vấn đề về bảo mật. Bytecode có thể được kiểm tra và phân tích trước khi thực hiện (nghĩa là, không có tràn bộ đệm, các biến của một kiểu nhất định đang được truy cập như một cái gì đó mà chúng không được), ...

+8

Đây là những tính năng hấp dẫn của VM - nhưng chúng gần như trực giao với OOP. – leonbloy

+0

Xác minh là không nhất thiết có thể, mã byte phải được thiết kế để cho phép nó. – ergosys

1

Bytecode là phương tiện linh hoạt hơn đáng kể so với mã máy. Đầu tiên, nó cung cấp cơ sở cho tính di động nền tảng mà không cần trình biên dịch hoặc mã nguồn vận chuyển. Vì vậy, nhà phát triển có thể phân phối một phiên bản ứng dụng duy nhất mà không cần phải từ bỏ nguồn, yêu cầu các công cụ nhà phát triển phức tạp hoặc dự đoán nền tảng mục tiêu tiềm năng. Trong khi sau này không phải lúc nào cũng thực tế nó xảy ra. Đặc biệt với các thư viện nhà phát triển nói rằng tôi phân phối một thư viện mà tôi đã chỉ thử nghiệm trên Windows, nhưng một người khác sử dụng nó trên Linux hoặc Android. Nó xảy ra khá thường xuyên thực sự, và hầu hết thời gian nó hoạt động như mong đợi.

Mã byte thường được tối ưu hóa thông thường hơn vì thông dịch viên vì nó gần với hướng dẫn máy hơn do đó dịch nhanh hơn sang hướng dẫn của máy. Không phải tất cả các ngôn ngữ OO đều được biên soạn. Ruby, Python và thậm chí Javascript được diễn giải để chúng không được biên dịch thành bất kỳ thứ gì, vì vậy trình thông dịch ruby ​​phải có ngôn ngữ rất linh hoạt và chuyển thành hướng dẫn, nhưng tính linh hoạt đó được trả một thời gian chạy: phân tích cú pháp văn bản, tạo AST, dịch AST thành mã máy, vv Nó cũng dễ dàng để tối ưu hóa như JIT nơi mã byte được dịch sang mã máy trực tiếp, và thậm chí cung cấp khả năng tạo tối ưu hóa cho phần cứng cụ thể.

Cuối cùng, chỉ vì một ngôn ngữ biên dịch sang bytecode không loại trừ các ngôn ngữ khác lợi dụng mã byte đó. Bây giờ bất kỳ tối ưu hóa nào sử dụng mã byte đó có thể được áp dụng cho các ngôn ngữ khác có thể biết cách dịch chính chúng sang mã byte đó. Điều đó làm cho mã byte trở thành một lớp rất quan trọng để có thể sử dụng lại cho các ngôn ngữ khác.

Biên dịch mã OO và byte quay trở lại những năm 70 bằng Smalltalk, và tôi chắc chắn ai đó sẽ nói LISP sớm nhất là 50 giây/60. Nhưng, thực sự không phải cho đến những năm 90 mà nó bắt đầu thực sự được sử dụng trong các hệ thống sản xuất trên quy mô lớn.

Biên dịch gốc có vẻ giống như con đường tối ưu, và có lẽ lý do tại sao ngành của chúng tôi dành 20 năm hoặc nhiều hơn suy nghĩ đó là TRẢ LỜI cho tất cả các vấn đề của chúng tôi, nhưng 15 năm qua chúng tôi đã xem biên dịch mã byte. lợi thế đáng kể so với những gì chúng tôi đã làm trước đây.Nhìn lại, chúng tôi nhận ra bao nhiêu thời gian lãng phí nguyên bản biên dịch tất cả mọi thứ chủ yếu bằng tay.

+1

LUA biên dịch thành bytecode và chạy trên máy ảo, nhưng cũng linh hoạt như Javascript, theo như cấu trúc chương trình. Tôi tin rằng (ít nhất một số) triển khai LISP làm điều này, là tốt. –

+1

Python _is_ được biên dịch. Điều này xảy ra khi bạn chạy tập lệnh, nếu nó không xảy ra trước đó. – knitti

+0

Để cụ thể hơn, Python biên dịch sang bytecode. –

3

Lý do lớn nhất tại sao hầu hết các ngôn ngữ thông dịch (không phải ngôn ngữ OO cụ thể) được biên dịch sang bytecode là để thực hiện. Phần tốn kém nhất của mã phiên dịch là chuyển đổi nguồn văn bản thành biểu diễn trung gian. Ví dụ, để thực hiện một cái gì đó như:

foo + bar; 

Thông dịch viên sẽ phải quét 10 ký tự, biến đổi chúng thành 4 thẻ, xây dựng một AST cho các hoạt động, giải quyết ba biểu tượng (+ là một biểu tượng, mà phụ thuộc vào các loại foo và bar), tất cả trước khi nó có thể thực hiện bất kỳ hành động nào thực sự phụ thuộc vào trạng thái thời gian chạy của chương trình. Không có điều nào trong số này có thể thay đổi từ khi chạy để chạy và rất nhiều ngôn ngữ cố gắng lưu trữ một số dạng biểu diễn trung gian.

bytecode, thay vì lưu trữ AST có một số lợi thế. Đối với một, bytecodes rất dễ dàng để tuần tự hóa, do đó, IR có thể được ghi vào đĩa và tái sử dụng tại lời gọi tiếp theo, tiếp tục giảm thời gian giải thích. Một lý do khác là bytecode thường chiếm ít ram thực tế hơn. biểu diễn bytecode đáng kể thường dễ dàng chỉ trong thời gian biên dịch, vì chúng thường có cấu trúc tương tự như mã máy điển hình.

+1

Dịch văn bản sang biểu diễn trung gian thường không phải là phần biên dịch đắt nhất. Tôi nghĩ rằng một vấn đề lớn hơn liên quan đến tra cứu. Nếu mã trong một tệp lớp sử dụng một trường của một lớp được định nghĩa trong một tệp khác và cả hai tệp được lưu trữ dưới dạng văn bản, thì độ phân giải của một truy cập trường duy nhất có thể yêu cầu quét toàn bộ tệp thứ hai. Ngược lại, một tập tin bytecode có thể bao gồm một danh sách các trường được định nghĩa trong một lớp và các địa chỉ của chúng, cũng như một danh sách các trường cấp ngoại được truy cập; thời gian chạy có thể sử dụng cả hai danh sách để xây dựng trong bộ nhớ một danh sách các địa chỉ trường nước ngoài. – supercat

1

Là một điểm dữ liệu khác, the D programming language là GC'ed, OO và cao hơn rất nhiều so với C++ trong khi vẫn đang được biên dịch thành mã gốc.

0

Tôi đồng ý với câu trả lời Chubbard và tôi muốn thêm rằng trong các ngôn ngữ OO gõ thông tin có thể rất quan trọng để cho phép tối ưu hóa bởi ảo-máy hoặc trình biên dịch cuối cấp

4

Java sử dụng bytecode vì hai trong số những mục tiêu thiết kế ban đầu của nó là tính di động và nhỏ gọn. Cả hai đều đến từ tầm nhìn ban đầu của một ngôn ngữ cho các thiết bị nhúng, nơi mà các đoạn mã có thể được tải xuống ngay lập tức.

Python, Ruby, Smalltalk, javascript, awk, v.v. sử dụng bytecode vì viết trình biên dịch gốc là rất nhiều công việc, nhưng trình thông dịch văn bản quá chậm - bytecode có vị trí khá dễ viết, nhưng cũng nhanh chóng chạy nhanh.

Tôi không biết tại sao các ngôn ngữ Microsoft sử dụng bytecode, vì đối với chúng, cả tính di động lẫn độ chặt đều là một vấn đề lớn. Rất nhiều suy nghĩ đằng sau CLR đến từ các nhà khoa học máy tính ở Cambridge, vì vậy tôi hình dung những cân nhắc như dễ phân tích và xác minh chương trình đã được tham gia.

Lưu ý rằng cũng như C++ và Mục tiêu C, Eiffel, Ada 9X, Vala và Go là các ngôn ngữ OO (có cổ điển khác nhau) được biên dịch thẳng sang mã gốc.

Tất cả trong tất cả, tôi muốn nói rằng OO và bytecode không đi đôi với nhau. Thay vào đó, chúng ta có một sự hội tụ ngẫu nhiên của một số luồng phát triển: các thông dịch viên mã hóa truyền thống của các ngôn ngữ kịch bản như Python và Ruby, kế hoạch tổng quát của Gosling của Java, và bất kể động cơ của Microsoft là gì.

+0

.Net của Microsoft cũng chạy trên các kiến ​​trúc không phải PC - Xbox360 và Windows Mobile 7, do đó có tính di động. –

+0

Tôi giả sử. Net biên dịch sang bytecode để tương thích với ngôn ngữ chéo – niagr

+0

@thelaststud: Vâng, đó có thể là nó. –

0

Việc phát triển trình thông dịch dễ dàng hơn trình biên dịch.

nỗ lực trong việc xây dựng ...:

thông dịch bytecode <-phiên dịch < bytecode-JIT-biên dịch < biên dịch-to-nền tảng độc lập ngôn ngữ < biên dịch-to-nhiều-máy-phụ thuộc lắp ráp.

Đó là xu hướng chung để ngăn chặn sự phát triển ở trình biên dịch jit vì nền tảng độc lập. Chỉ có các ngôn ngữ ưu tiên liên quan đến hiệu suất và nghiên cứu trong khoa học máy tính lý thuyết và sẽ được phát triển theo mọi hướng có thể, bao gồm cả phiên dịch viên bytecode mới, ngay cả khi có trình biên dịch tốt và nâng cao để nền tảng ngôn ngữ độc lập và các trình lắp ráp phụ thuộc vào máy khác nhau.

Nghiên cứu ngôn ngữ OOP khá ... giả sử, so với ngôn ngữ chức năng, bởi vì công nghệ trình biên dịch và ngôn ngữ mới dễ dàng được thể hiện bằng/trong/sử dụng lý thuyết cathegory toán học và mô tả toán học -systems. Nói cách khác: nó gần như là chức năng trong chính nó, trong khi các ngôn ngữ mệnh lệnh gần như chỉ có các giao diện lắp ráp với một số đường cú pháp. Ngôn ngữ OOP có xu hướng là ngôn ngữ bắt buộc, bởi vì các ngôn ngữ chức năng đã đóng và lambda. Có nhiều cách khác để thực hiện "giao diện" giống java trong các ngôn ngữ chức năng, và không chỉ cần thêm các tính năng hướng đối tượng bổ sung.

Trong Haskell, việc thêm tính năng của chương trình giống như OOP có thể sẽ không chỉ bằng một vài bước trong công nghệ - sẽ không có điểm nào khi sử dụng công nghệ đó. (< - đó không chỉ là IMHO ... mà bạn từng nghe về GADT hoặc nhiều loại tham số?) Có lẽ có những cách tốt hơn để tự động tạo đối tượng với giao diện để giao tiếp với OOP-languges thay vì tự thay đổi ngôn ngữ đó . Nhưng cũng có các ngôn ngữ chức năng khác, kết hợp rõ ràng các khía cạnh chức năng và OOP. Chỉ có nhiều khoa học hơn với ngôn ngữ chủ yếu là chức năng hơn là các ngôn ngữ OO không hoạt động.

Các ngôn ngữ OO không thể dễ dàng được biên dịch sang các ngôn ngữ OO khác, tức là chúng ở một số cách "nâng cao" hơn. Thông thường, chúng có các tính năng như ngăn xếp ngăn xếp, khả năng gỡ lỗi nâng cao, đa luồng trừu tượng và có thể kiểm tra, tải đối tượng động từ các tệp từ internet ... Nhiều tính năng này không hoặc không dễ dàng thực hiện được với C hoặc C++ làm trình biên dịch -backend. LISP ngôn ngữ chức năng (50 năm tuổi!) Là AFAIK đầu tiên với bộ thu gom rác. Khi LISP trình biên dịch phụ trợ sử dụng phiên bản tấn công của ngôn ngữ C, bởi vì đồng bằng C không cho phép một số thứ đó, assembly đã cho phép, tức là các cuộc gọi thích hợp hoặc các bảng-tiếp-nối-mã. C-- cho phép điều đó.

Một khía cạnh khác: Các ngôn ngữ bắt buộc được dự định chạy trên một kiến ​​trúc cụ thể, tức là các chương trình C và C++ chỉ chạy trên các kiến ​​trúc đó, chúng được lập trình. Java là cực đoan hơn: nó chỉ chạy trên một kiến ​​trúc duy nhất, một ảo, mà chính nó chạy trên những người khác. Ngôn ngữ chức năng thường được thiết kế độc lập với kiến ​​trúc khá độc đáo: LISP được phát triển để có kiến ​​trúc to lớn đến mức không thể xác định, nó có thể được biên dịch thành mã di truyền, trong một tương lai xa xôi. Có, giống như các chương trình chạy trong các tế bào sinh học sống.

Với mã byte cho LLVM, các ngôn ngữ chức năng sẽ được biên dịch thành bytecode trong tương lai. Hầu hết các ngôn ngữ bắt buộc sẽ có nhiều khả năng vẫn còn có cùng các vấn đề di truyền như chúng bây giờ không từ trừu tượng đến nay. Vâng, tôi không chắc chắn về clang và D, nhưng hai người đó không phải là "nhiều nhất".

+1

Cũng giống như một lưu ý phụ, việc đọc này sẽ tốt hơn nếu bạn sửa lỗi chính tả của mình. – ocodo

+0

Trớ trêu thay, tôi không hiểu ý nghĩa của đề xuất của bạn. Tôi không phải là người nói tiếng Anh tự nhiên; "(để) sửa lỗi chính tả" nghĩa là gì? – comonad

+0

@slomojo - Điều anh ta có nghĩa là câu trả lời của bạn có rất nhiều lỗi chính tả IE: ** cathegory-> category ** – ChaosPandion

Các vấn đề liên quan