Chrome V8 hoạt động như thế nào? Và tại sao JavaScript không được biên dịch JIT ngay từ đầu?


19

Tôi đã nghiên cứu Trình thông dịch / Trình biên dịch, sau đó tôi tình cờ tìm thấy Trình biên dịch JIT - cụ thể là Công cụ Javascript V8 của Google Chrome.

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

  1. Làm thế nào nó có thể nhanh hơn Giải thích tiêu chuẩn?
  2. Tại sao không phải là JIT-Compilation được sử dụng ở nơi đầu tiên?


Hiểu biết hiện tại của tôi

  1. Mỗi chương trình Javascript bắt đầu dưới dạng mã nguồn , sau đó, bất kể phương thức thực hiện, cuối cùng được dịch sang mã máy .
    Cả JIT-CompilationInterpretation đều phải đi theo con đường này, vậy làm thế nào để JIT-Compilation có thể nhanh hơn (cũng bởi vì JIT bị hạn chế về thời gian, không giống như AOT-Compilation)?

  2. Có vẻ như JIT-Compilation là một sự đổi mới tương đối cũ , dựa trên Điều khoản tổng hợp JIT của Wikipedia .

"Trình biên dịch JIT được xuất bản sớm nhất thường được quy cho hoạt động trên LISP của McCarthy vào năm 1960. "

"Smalltalk (c. 1983 ) đã tiên phong trong các khía cạnh mới của các phần tổng hợp JIT. Ví dụ, dịch mã sang mã máy được thực hiện theo yêu cầu và kết quả được lưu vào bộ nhớ cache để sử dụng sau này. Khi bộ nhớ trở nên khan hiếm, hệ thống sẽ xóa một số mã này và tạo lại nó khi cần thiết một lần nữa. "

Vậy tại sao Javascript được giải thích để bắt đầu ?


Tôi rất bối rối, và tôi đã thực hiện rất nhiều nghiên cứu về vấn đề này, nhưng tôi chưa tìm thấy câu trả lời thỏa đáng.

Vì vậy, câu trả lời rõ ràng, súc tích sẽ được đánh giá cao. Và nếu cần giải thích thêm về Thông dịch viên, Trình biên dịch JIT, v.v., thì điều đó cũng được đánh giá cao.


2
# 2 và # 3 có thể trả lời được, nhưng "Chrome V8 Engine hoạt động như thế nào?" không có bất kỳ trình độ nào là quá rộng; câu trả lời đúng duy nhất là một liên kết đến mã nguồn V8. Ý của bạn là hỏi một cái gì đó cụ thể hơn về V8? (nếu không, tốt nhất là xóa phần đó của câu hỏi)
Ixrec 29/07/2015

Ở cái nhìn thứ hai, điểm duy nhất của tôi hỏi # 1 là hiểu # 2, vì vậy tôi sẽ loại bỏ nó. Cảm ơn các đầu vào.
Anton Paras

Điều này không được đề cập trong các câu trả lời khác nhưng biên dịch JIT là khó. Đó không phải là điều đơn giản để làm vì các lỗi phát sinh từ quá trình biên dịch JIT dẫn đến lỗi phân tách thay vì lỗi - chương trình gặp sự cố thay vì ném lỗi trong bảng điều khiển. Có, đối với một lập trình viên C có thẩm quyền thoải mái với gdb thì đây không phải là vấn đề. Nhưng hầu như tất cả các lập trình viên C có thẩm quyền thoải mái với gdb được trả tiền để làm việc trên các dự án khác. Một số ngôn ngữ khác như Perl và Ruby vẫn không có trình thông dịch JIT chính thống.
slebetman

Trong trường hợp bạn đang tự hỏi. Tôi đang nói về điều này từ quan điểm của một nhà phát triển / bảo trì cốt lõi cho ngôn ngữ lập trình. Trong một vài năm, tôi đã được thuê để duy trì ngôn ngữ lập trình Ferite. Một trong những danh sách mong muốn mà chúng tôi có là triển khai JIT. Nó không bao giờ xảy ra - chúng tôi di chuyển để đi thay thế. PHP gần đây mới có trình biên dịch JIT (HVVM) nhờ Facebook rót đủ tiền vào nó để thực hiện.
slebetman

Câu trả lời:


43

Câu trả lời ngắn gọn là JIT có thời gian khởi tạo lâu hơn, nhưng nhanh hơn rất nhiều trong thời gian dài và JavaScript ban đầu không nhằm mục đích lâu dài.

Vào những năm 90, JavaScript điển hình trên một trang web sẽ có tới một hoặc hai chức năng trong tiêu đề và một số ít mã được nhúng trực tiếp vào onclickcác thuộc tính và tương tự. Nó thường sẽ được chạy đúng khi người dùng đang mong đợi một sự chậm trễ tải trang lớn. Hãy suy nghĩ xác thực mẫu cực kỳ cơ bản hoặc các tiện ích toán học nhỏ như máy tính lãi suất thế chấp.

Phiên dịch khi cần thiết đơn giản hơn rất nhiều và cung cấp hiệu suất hoàn toàn phù hợp cho các trường hợp sử dụng trong ngày. Nếu bạn muốn một cái gì đó với hiệu suất dài hạn, bạn đã sử dụng flash hoặc một applet java.

Bản đồ Google năm 2004 là một trong những ứng dụng sát thủ đầu tiên sử dụng JavaScript nặng. Nó đã được mở rộng cho các khả năng của JavaScript, nhưng cũng nhấn mạnh các vấn đề về hiệu suất của nó. Google đã dành thời gian cố gắng khuyến khích các trình duyệt cải thiện hiệu suất JavaScript của họ, sau đó cuối cùng quyết định cạnh tranh sẽ là động lực tốt nhất và cũng sẽ cung cấp cho họ chỗ ngồi tốt nhất trong bảng tiêu chuẩn trình duyệt. Kết quả là Chrome và V8 đã được phát hành vào năm 2008. Bây giờ, 11 năm sau khi Google Maps xuất hiện, chúng tôi có những nhà phát triển mới không nhớ JavaScript từng bị coi là không phù hợp với loại nhiệm vụ đó.

Nói rằng bạn có một chức năng animateDraggedMap. Có thể mất 500 ms để diễn giải nó và 700 ms để JIT biên dịch nó. Tuy nhiên, sau khi biên dịch JIT, có thể chỉ mất 100 ms để thực sự chạy. Nếu đó là những năm 90 và bạn chỉ gọi một chức năng một lần rồi tải lại trang, thì JIT hoàn toàn không xứng đáng. Nếu đó là ngày hôm nay và bạn đang gọi animateDraggedMaphàng trăm hoặc hàng nghìn lần, thì thêm 200 ms khi khởi tạo là không có gì, và nó có thể được thực hiện phía sau hậu trường trước khi người dùng thậm chí cố gắng kéo bản đồ.


2

Với sự hiểu biết về những gì đang diễn ra trong thời gian chạy, có thể thực hiện thay đổi mã hoặc giải thích mã cho phép nó được thực thi nhanh hơn hoặc được biên dịch tốt hơn những gì đã biết trước thời gian biên dịch.

Có thể nói một chút về điều này - đó là chủ đề của số lượng nghiên cứu đáng kể. Giải thích riêng của tôi ở đây là tôi bắt đầu viết truyện so với câu trả lời trong Tìm hiểu sự khác biệt: trình thông dịch truyền thống, trình biên dịch JIT, trình thông dịch JIT và trình biên dịch AOT


Nói một cách đơn giản, JavaScript ban đầu không được biên dịch hoặc xem xét cho JIT vì nó không bao giờ có nghĩa là bất cứ điều gì phức tạp hoặc quan trọng.

Mục đích ban đầu của Java Script là liên kết với các applet Java trên một trang web. Khả năng nhấp vào một số nút hoặc nhập một giá trị trong trường biểu mẫu và sau đó thực hiện công việc trong phương thức applet Java có thể được nhìn thấy trong Gọi phương thức Applet từ mã JavaScript . Cũng có thể, thông qua JavaScript để đi theo cách khác để gọi mã JavaScript từ một applet .

Mục đích ban đầu của JavaScript là liên kết các applet và các trang html chứa chúng. Đối với một nhiệm vụ nhỏ như vậy, người ta không cần hiệu năng tuyệt vời (nếu bạn muốn hiệu suất, hãy gọi phương thức applet là JIT'ed).

Chỉ sau khi Netscape bắt đầu thực hiện công việc quan trọng với JavaScript như ngôn ngữ của chính nó và thúc đẩy nó phát triển (bao gồm cả JavaScript phía máy chủ trong Netscape Enterprise Server - điều mà, tình cờ đã đi trước thời gian biên dịch), JavaScript đã trở thành mục tiêu nghiêm trọng . Phải mất nhiều năm sau đó, các công cụ cần thiết để làm cho nó hữu ích.


1
Không, Javascript không liên quan đến Java. Và các applet Java là mã byte JVM.
Stilenkevitch Basile

@BasileStarynkevitch JavaScript được thiết kế để hoạt động với các applet Java trong các trang ấp - đóng vai trò là chất kết dính giữa dom html và các phương thức có trong các đối tượng Java. Nó không phải và không bao giờ có ý định trở thành Java.

JavaScript ban đầu được gọi là ECMAScript (hoặc một cái gì đó tương tự) và không liên quan gì đến Java. Làm thế nào nó được gọi là JavaScript là chủ đề của nghiên cứu riêng biệt cho những người quan tâm. Điều này đã gây ra sự nhầm lẫn từ bao giờ trở đi.
quick_now

1
@quickly_now và vẫn là tc39.github.io/ecma262
caub

Đúng. Và vì một số lý do kỳ quặc khi tôi chỉ ra rằng tôi đã bị hạ thấp vì nó!
quick_now

1

JIT nhanh cho JavaScript, vì không thể tạo mã máy nhanh khi bạn không biết loại biến của mình.

Khi bạn không có thông tin loại, tính toán rất tốn kém. Ví dụ,

x + y

khá phức tạp nếu bạn không biết gì về x và y. Chúng có thể là số nguyên, nhân đôi, chuỗi hoặc thậm chí là các đối tượng trong đó phép tính này có tác dụng phụ. Vì chúng ta không có kiểu gõ tĩnh, đây là một phép tính đắt tiền.

Với việc biên dịch đúng lúc, chúng ta có thể sử dụng thông tin thời gian chạy và biến điều này thành một tính toán nhanh hơn. Trong thời gian chạy, V8 theo dõi các loại biến. Nếu đoạn mã trên được thực thi nhiều lần với các chuỗi, trình biên dịch, trình biên dịch có thể thực thi các hướng dẫn đơn giản hơn nhiều để nối chuỗi. Vì vậy, khi trình biên dịch đạt tới x + y, thay vì chạy nhiều mã phân nhánh cho nhiều loại x và y khác nhau, trình biên dịch sẽ nhanh chóng kiểm tra xem chúng ta có lại chuỗi không, và sau đó thực thi chỉ một vài dòng mã máy cụ thể nối chuỗi.

Ví dụ, C ++ trình biên dịch biết các loại x và y trước thời hạn, vì chúng ta phải khai báo các biến. Vì vậy, nó có thể tạo mã máy được tối ưu hóa để nối chuỗi trước khi chạy mã.


0

1) Làm thế nào nó có thể nhanh hơn Giải thích tiêu chuẩn? Vâng, một ví dụ lên suy nghĩ sẽ như sau; giả sử chúng ta có 2 ứng dụng ApplicationCompiled và ApplicationInterpratted. Cả hai chương trình này đều thực hiện chính xác cùng một thứ và chia sẻ cùng một mã nguồn. ApplicationCompiled mất 6 giây để biên dịch.

Hãy nói rằng thời gian của Kịch bản A là:

  • Đối với ApplicationCompiled: 4 giây
  • Đối với ApplicationInterprposed: 12 giây

Vì vậy, trong tổng số ApplicationCompiled mất 10 giây để chạy Kịch bản A (biên dịch 6 giây, chạy 4 giây) và ApplicationInterpratted mất tổng cộng 12 giây để chạy. Tôi không có một ví dụ cụ thể để chỉ cho bạn và tôi không chắc trong trường hợp nào những điều trên là đúng - nó cũng phụ thuộc rất nhiều vào mức độ thông minh và trình biên dịch.

Rõ ràng điều này rất đơn giản, nhưng ý tưởng tương tự có thể được áp dụng cho việc biên dịch / phiên dịch JIT. Câu hỏi tiếp theo sau đó sẽ là "làm thế nào để chúng tôi xác định - với chi phí thấp - nếu chi nhánh này nên được biên dịch hoặc giải thích"? Tôi ra khỏi giải đấu của tôi ở đây :)

2) Tại sao không phải là JIT-Compilation được sử dụng ở nơi đầu tiên? Không biết, nhưng tôi chỉ đơn giản là vấn đề tài nguyên và sự trưởng thành của tiến trình có sẵn trong việc tạo ra một ngôn ngữ khó tối ưu hóa như JavaScript áp dụng các kỹ thuật tiến bộ như thế này. Có lẽ có rất nhiều trái cây treo thấp hơn vào thời điểm đó.

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.