2010-12-23 41 views
13

thể trùng lặp:
JIT compiler vs offline compilerskhi nào java nhanh hơn C++ (hoặc khi nào JIT nhanh hơn được biên dịch trước)?

Tôi đã nghe nói rằng trong những trường hợp nhất định, các chương trình Java hay đúng hơn là một phần của chương trình java có thể được thực hiện nhanh hơn so với "giống nhau" mã trong C++ (hoặc mã biên dịch khác) do tối ưu hóa JIT. Điều này là do trình biên dịch có thể xác định phạm vi của một số biến, tránh một số điều kiện và kéo các thủ thuật tương tự khi chạy.

Bạn có thể cung cấp một (hoặc tốt hơn - một số ví dụ), nơi áp dụng điều này không? Và có thể phác thảo các điều kiện chính xác mà theo đó trình biên dịch có thể tối ưu hóa bytecode vượt quá những gì có thể với mã biên dịch trước?

LƯU Ý: Câu hỏi này là không phải là về cách so sánh Java với C++. Đó là về khả năng biên dịch JIT. Xin vui lòng không có lửa. Tôi cũng không biết bất kỳ bản sao nào. Hãy chỉ ra chúng nếu bạn đang có.

+0

điều này hóa ra là một bản sao. xin lỗi vì sự bất tiện. hãy hợp nhất – kostja

Trả lời

33

Trong thực tế, bạn có khả năng tìm mã Java ngây thơ bằng văn bản của bạn làm tốt hơn ngây thơ viết mã C++ của bạn trong những tình huống này (tất cả trong đó cá nhân tôi đã quan sát):

  • Rất nhiều cấp phát bộ nhớ ít/deallocations. Các JVM chính có hệ thống con bộ nhớ cực kỳ hiệu quả, và việc thu gom rác có thể hiệu quả hơn yêu cầu giải phóng rõ ràng (cộng với nó có thể thay đổi địa chỉ bộ nhớ và nếu nó thực sự muốn).

  • Truy cập hiệu quả thông qua phân cấp sâu của các cuộc gọi phương thức. JVM là rất tốt ở eliding bất cứ điều gì đó là không cần thiết, thường là tốt hơn trong kinh nghiệm của tôi so với hầu hết các trình biên dịch C++ (bao gồm cả gcc và icc). Một phần điều này là bởi vì nó có thể phân tích động tại thời gian chạy (nghĩa là nó có thể overoptimize và chỉ deoptimize nếu nó phát hiện một vấn đề).

  • Đóng gói chức năng thành các đối tượng sống ngắn.

Trong mỗi trường hợp, nếu bạn đặt các nỗ lực trong, C++ có thể làm tốt hơn (giữa danh sách miễn phí và/bộ nhớ deallocated khối phân bổ, C++ có thể đánh bại các hệ thống bộ nhớ JVM trong hầu hết các trường hợp cụ thể; với mã thêm , các mẫu và các macro thông minh, bạn có thể thu gọn ngăn xếp cuộc gọi một cách hiệu quả và bạn có thể có các đối tượng được phân bổ một phần nhỏ được khởi tạo trong C++ tốt hơn mô hình đối tượng sống ngắn của JVM). Nhưng có thể bạn không muốn đặt nỗ lực vào.

+1

cảm ơn bạn. đây là mức độ chi tiết tôi hy vọng. – kostja

5

Wikipedia: http://en.wikipedia.org/wiki/Just-in-time_compilation#Overview

Bên cạnh đó, nó có thể trong một số trường hợp hiệu suất phục vụ tốt hơn so với biên soạn tĩnh, như nhiều tối ưu hóa chỉ khả thi ở thời gian chạy:

  1. Biên dịch có thể là được tối ưu hóa cho CPU được nhắm mục tiêu và mô hình hệ điều hành nơi ứng dụng chạy. Ví dụ JIT có thể chọn lệnh CPU SSE2 khi phát hiện CPU hỗ trợ chúng. Để có được mức độ tối ưu hóa đặc trưng này với trình biên dịch tĩnh, người ta phải biên dịch nhị phân cho mỗi nền tảng/kiến ​​trúc dự định, hoặc bao gồm nhiều phiên bản của các phần của mã trong một nhị phân đơn. hệ thống

  2. là thể thu thập thống kê về cách thức chương trình được thực sự chạy trong môi trường đó là trong, và nó có thể sắp xếp lại và biên dịch lại cho hiệu suất tối ưu. Tuy nhiên, một số trình biên dịch tĩnh cũng có thể lấy thông tin hồ sơ làm đầu vào.

  3. Hệ thống có thể làm tối ưu hóa mã toàn cầu (ví dụ: nội tuyến chức năng thư viện) mà không làm mất lợi thế của liên kết động và không có chi phí vốn có cho trình biên dịch tĩnh và trình liên kết. Cụ thể, khi thực hiện thay thế nội tuyến toàn cục, quy trình biên dịch tĩnh có thể cần kiểm tra thời gian chạy và đảm bảo rằng cuộc gọi ảo sẽ xảy ra nếu lớp thực tế của đối tượng ghi đè phương thức được inlined và kiểm tra điều kiện biên trên truy cập mảng có thể cần được xử lý trong vòng lặp. Với việc biên dịch trong thời gian ngắn trong nhiều trường hợp, , quá trình xử lý này có thể được di chuyển ra khỏi vòng lặp, thường cho tốc độ tăng lớn của tốc độ.

  4. Mặc dù điều này là có thể với các ngôn ngữ thu thập rác được biên dịch tĩnh, hệ thống bytecode có thể dễ dàng sắp xếp lại mã được thực thi để sử dụng bộ nhớ cache tốt hơn.

+3

Thông tin tuyệt vời, nhưng đọc kỹ cho thấy rằng biên dịch trước thực sự có thể và thực hiện nhiều tối ưu hóa "chỉ dành cho JIT". –

+1

@BenVoigt Đó là một điểm tốt. Đối số còn lại chính là JIT có quyền truy cập thông tin cụ thể cho tiến trình đang chạy, thay vì một hồ sơ được tạo trước hoặc tương tự. Do đó, nó có thể thực hiện tối ưu hóa táo bạo thường xuyên hơn và có nhiều cơ hội thành công hơn. –

6

Một số ví dụ:

  • Trình biên dịch JIT có thể sản xuất rất CPU cụ thể mã máy sử dụng ví dụ các phần mở rộng SSE mới nhất mà một trong những sẽ không sử dụng trong mã biên dịch sẵn mà cần phải chạy một loạt các CPU.
  • JIT biết khi một phương thức ảo (mặc định trong Java) không được ghi đè ở bất kỳ đâu, và do đó có thể được gạch chân (mặc dù điều này đòi hỏi khả năng bỏ liên kết khi một lớp mới được nạp mà không ghi đè phương thức; Java JIT trình biên dịch thực sự làm điều này).
  • Liên quan đến điều đó, escape analysis cho phép tối ưu hóa theo từng tình huống cụ thể.
+0

Điểm đầu tiên là bổ sung hợp lệ như nhiều thư viện Java, nơi được viết trước khi các kiến ​​trúc CPU mới có sẵn. Những thư viện cũ này vẫn sử dụng những cải tiến CPu mới nhất. Để sử dụng kiến ​​trúc mới nhất trong C++, bạn phải có khả năng biên dịch từ nguồn mà nhiều người không thể thực hiện được/thực tiễn với các thư viện của bên thứ ba. đặc biệt nếu nhà phát triển không phải là người dùng cuối. ví dụ. bạn có một ứng dụng phải được triển khai cho nhiều loại máy tính khác nhau, có thể là một cơn ác mộng để giải phóng mọi nền tảng có thể, do đó, người tiêu biểu phổ biến nhất thường được chọn. –

+0

Tôi tin rằng JIT có thể thực hiện nội tuyến đa hình. tôi.e nó biết đến hai phương pháp "ảo" có thể được gọi là và chúng có thể được gạch chân và nếu đối tượng không phải là một trong các lớp này thì sẽ bị thu gọn. Điều này có nghĩa là ngay cả các phương pháp ảo với nhiều triển khai có thể có thể được nội tuyến dựa trên hành vi thời gian chạy. –

+1

Trình tối ưu hóa có hướng dẫn sử dụng C++ sử dụng các thủ thuật tương tự này. –

0

Xử lý sự cố bộ nhớ của Java nhanh hơn đáng kể so với C++. Xem Java theory and practice: Urban performance legends, revisited.

+0

một liên kết tốt đôi khi tốt như câu trả lời có thể nhận được. rất sâu sắc. cảm ơn bạn – kostja

+5

Lý lẽ người đàn ông rơm đẹp. C++ không yêu cầu bạn sử dụng 'malloc', xem ví dụ như trình phân bổ pool của wireshark. –

+0

vì vậy đối số không áp dụng cho phân bổ C++ với mới? Có phải vì đống phân bổ bởi HeapAlloc và giống nhau được sử dụng để phân bổ với mới? – kostja

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