Trình biên dịch JIT khác với trình biên dịch thông thường như thế nào?


22

Đã có rất nhiều sự cường điệu về trình biên dịch JIT cho các ngôn ngữ như Java, Ruby và Python. Trình biên dịch JIT khác với trình biên dịch C / C ++ như thế nào và tại sao trình biên dịch được viết cho Java, Ruby hoặc Python được gọi là trình biên dịch JIT, trong khi trình biên dịch C / C ++ chỉ được gọi là trình biên dịch?

Câu trả lời:


17

Trình biên dịch JIT biên dịch mã khi đang thực hiện, ngay trước khi thực thi hoặc ngay cả khi chúng đang thực thi. Theo cách này, VM nơi mã đang chạy có thể kiểm tra các mẫu trong quá trình thực thi mã để cho phép tối ưu hóa chỉ có thể có với thông tin thời gian chạy. Hơn nữa, nếu VM quyết định rằng phiên bản đã biên dịch không đủ tốt vì bất kỳ lý do gì (ví dụ: quá nhiều lỗi bộ nhớ cache hoặc mã thường xuyên ném một ngoại lệ cụ thể), thì nó có thể quyết định biên dịch lại theo cách khác, dẫn đến thông minh hơn nhiều biên soạn.

Mặt khác, trình biên dịch C và C ++ theo truyền thống không phải là JIT. Họ biên dịch trong một lần bắn duy nhất một lần trên máy của nhà phát triển và sau đó một tệp thực thi được sản xuất.


Có trình biên dịch JIT nào theo dõi các lỗi bộ nhớ cache và điều chỉnh chiến lược biên dịch của chúng cho phù hợp không? @Victor
Martin Berger

@MartinBerger Tôi không biết nếu có bất kỳ trình biên dịch JIT nào có thể làm điều đó nhưng tại sao không? Khi máy tính mạnh hơn và khoa học máy tính phát triển, mọi người có thể áp dụng tối ưu hóa hơn cho chương trình. Ví dụ: khi Java ra đời, nó rất chậm, có thể gấp 20 lần so với các trình biên dịch nhưng bây giờ hiệu năng không bị tụt quá nhiều và có thể so sánh với một số trình biên dịch
phuclv

Tôi đã nghe điều này trên một số bài đăng blog từ lâu. Trình biên dịch có thể biên dịch khác nhau tùy thuộc vào CPU hiện tại. Ví dụ, nó có thể tự động vector hóa một số mã nếu phát hiện CPU hỗ trợ SSE / AVX. Khi có các tiện ích mở rộng SIMD mới hơn, nó có thể biên dịch sang các tiện ích mở rộng mới hơn để lập trình viên không cần thay đổi bất cứ điều gì. Hoặc nếu nó có thể sắp xếp các hoạt động / dữ liệu để tận dụng bộ đệm lớn hơn hoặc để giảm lỗi bộ nhớ cache
phuclv

@ LưuViênPhúc Chào! Tôi rất vui khi tin điều đó, nhưng sự khác biệt là, ví dụ như loại CPU hoặc kích thước bộ đệm là thứ gì đó không thay đổi trong suốt quá trình tính toán, do đó cũng có thể dễ dàng thực hiện bởi trình biên dịch tĩnh. Cache nhớ OTOH rất năng động.
Martin Berger

12

JIT là viết tắt của trình biên dịch chỉ trong thời gian và tên là misson: trong thời gian chạy, nó xác định tối ưu hóa mã đáng giá và áp dụng chúng. Nó không thay thế trình biên dịch thông thường mà là một phần của trình thông dịch. Lưu ý rằng các ngôn ngữ như Java sử dụng mã trung gian có cả hai : trình biên dịch thông thường để dịch mã nguồn sang trung gian và JIT có trong trình thông dịch để tăng hiệu suất.

Tối ưu hóa mã chắc chắn có thể được thực hiện bởi trình biên dịch "cổ điển", nhưng lưu ý sự khác biệt chính: Trình biên dịch JIT có quyền truy cập vào dữ liệu khi chạy. Đây là một lợi thế rất lớn ; Khai thác nó đúng cách có thể khó, rõ ràng.

Hãy xem xét, ví dụ, mã như thế này:

m(a : String, b : String, k : Int) {
  val c : Int;
  switch (k) {
    case 0 : { c = 7; break; }
    ...
    case 17 : { c = complicatedMethod(k, a+b); break; }
  }

  return a.length + b.length - c + 2*k;
}

Một trình biên dịch bình thường không thể làm quá nhiều về điều này. Tuy nhiên, một trình biên dịch JIT có thể phát hiện ra rằng mnó chỉ được gọi với k==0một số lý do (những thứ như thế có thể xảy ra khi mã thay đổi theo thời gian); sau đó nó có thể tạo một phiên bản mã nhỏ hơn (và biên dịch nó thành mã gốc, mặc dù tôi coi đây là một điểm nhỏ, về mặt khái niệm):

m(a : String, b : String) {
  return a.length + b.length - 7;
}

Tại thời điểm này, nó có thể thậm chí sẽ thực hiện cuộc gọi phương thức vì nó là tầm thường bây giờ.

Rõ ràng, Mặt trời đã loại bỏ hầu hết các tối ưu hóa javacđược sử dụng trong Java 6; Tôi đã được thông báo rằng những tối ưu hóa đó khiến JIT khó có thể làm được gì nhiều, và mã được biên dịch ngây thơ chạy nhanh hơn cuối cùng. Đi hình.


Nhân tiện, với sự hiện diện của kiểu xóa (ví dụ: generic trong Java), JIT thực sự là một kiểu wrt bất lợi.
Raphael

Vì vậy, thời gian chạy phức tạp hơn so với ngôn ngữ được biên dịch vì môi trường thời gian chạy phải thu thập dữ liệu để tối ưu hóa.
saadtaame

2
Trong nhiều trường hợp, JIT sẽ không thể thay thế mbằng phiên bản không kiểm tra kvì không thể chứng minh rằng msẽ không bao giờ được gọi bằng số không k, nhưng ngay cả khi không thể chứng minh rằng nó có thể thay thế nó với static miss_count; if (k==0) return a.length+b.length-7; else if (miss_count++ < 16) { ... unoptimized code for m ...} else { ... consider other optimizations...}.
supercat

1
Tôi đồng ý với @supercat và nghĩ rằng ví dụ của bạn thực sự khá sai lệch. Chỉ khi k=0 luôn luôn , có nghĩa là nó không phải là một chức năng của đầu vào hoặc môi trường, thì có an toàn khi bỏ thử nghiệm hay không - nhưng việc xác định điều này đòi hỏi phải phân tích tĩnh, rất tốn kém và do đó chỉ có giá cả phải chăng trong thời gian biên dịch. Một JIT có thể giành chiến thắng khi một đường dẫn qua một khối mã được thực hiện thường xuyên hơn nhiều so với các đường dẫn khác và một phiên bản mã dành riêng cho đường dẫn này sẽ nhanh hơn nhiều. Nhưng JIT vẫn sẽ phát ra một bài kiểm tra để kiểm tra xem đường dẫn nhanh có áp dụng hay không và thực hiện "đường dẫn chậm" nếu không.
j_random_hacker

Một ví dụ: Một hàm lấy một Base* ptham số và gọi các hàm ảo thông qua nó; phân tích thời gian chạy cho thấy rằng đối tượng thực tế luôn luôn chỉ (hoặc gần như luôn luôn) dường như là Derived1loại. JIT có thể tạo ra một phiên bản mới của hàm với các lệnh gọi được giải quyết tĩnh (hoặc thậm chí là nội tuyến) Derived1. Mã này sẽ được đi trước bởi một điều kiện để kiểm tra xem pcon trỏ vtable của nó có trỏ đến Derived1bảng dự kiến ​​hay không ; nếu không, nó thay vào đó nhảy sang phiên bản gốc của hàm với các lệnh gọi phương thức được giải quyết động chậm hơn.
j_random_hacker
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.