Tại sao Java có thể nhanh hơn C ++?


79

Đôi khi Java vượt trội hơn C ++ về điểm chuẩn. Tất nhiên, đôi khi C ++ vượt trội hơn.

Xem các liên kết sau:

Nhưng làm thế nào điều này thậm chí có thể? Nó làm tôi suy nghĩ rằng mã byte được giải thích có thể nhanh hơn ngôn ngữ được biên dịch.

Ai đó có thể vui lòng giải thích? Cảm ơn!


2
Bạn có thể xem qua shotout.alioth.debian.org/u32/, để xem loại sự cố chạy nhanh hơn trên java / c ++ ... Xem mô hình sự cố và không phải là các sự cố cụ thể này ...
c0da

2
Xem tại sao java có tiếng là chậm? cho rất nhiều chi tiết về chủ đề này.
Péter Török

11
Nó là trái luật (Phần 10.101.04.2c) để tạo ra một máy ảo Java mà thực hiện nhanh hơn so với một thực thi nhị phân được sản xuất với C ++.
Mateen Ulhaq

1
@muntoo Ý bạn là gì? Mục 10.101.04.2c của cái gì?
Cao nguyên Mark

3
@HighlandMark Bạn không phải là thành viên của vòng tròn. Bạn không biết những gì đi vào vòng tròn. Vòng tròn là tuyệt đối - quy luật của vòng tròn áp đảo so với tự nhiên. Bạn không thể thách thức cũng không đặt câu hỏi về vòng tròn. Tôi là vòng tròn và vòng tròn là tôi.
Mateen Ulhaq

Câu trả lời:


108

Đầu tiên, hầu hết các JVM đều bao gồm một trình biên dịch, do đó "mã byte được giải thích" thực sự khá hiếm (ít nhất là trong mã điểm chuẩn - nó không hoàn toàn hiếm trong cuộc sống thực, nơi mã của bạn thường nhiều hơn một vài vòng lặp thường được lặp lại thường xuyên ).

Thứ hai, một số lượng lớn các điểm chuẩn liên quan dường như khá sai lệch (cho dù do cố ý hay không đủ năng lực, tôi thực sự không thể nói). Ví dụ, nhiều năm trước tôi đã xem xét một số mã nguồn được liên kết từ một trong những liên kết bạn đã đăng. Nó có mã như thế này:

  init0 = (int*)calloc(max_x,sizeof(int));
  init1 = (int*)calloc(max_x,sizeof(int));
  init2 = (int*)calloc(max_x,sizeof(int));
  for (x=0; x<max_x; x++) {
    init2[x] = 0;
    init1[x] = 0;
    init0[x] = 0;
  }

Vì việc calloccung cấp bộ nhớ đã bị xóa không, sử dụng forvòng lặp về 0 nên rõ ràng là vô dụng. Điều này đã được theo dõi (nếu bộ nhớ phục vụ) bằng cách lấp đầy bộ nhớ với dữ liệu khác (và không phụ thuộc vào nó bằng 0), do đó, tất cả các zeroing là hoàn toàn không cần thiết. Việc thay thế mã ở trên bằng một cách đơn giản malloc(giống như bất kỳ người lành mạnh nào đã từng sử dụng để bắt đầu) đã cải thiện tốc độ của phiên bản C ++ đủ để đánh bại phiên bản Java (bằng một lề khá rộng, nếu bộ nhớ phục vụ).

Xem xét (cho một ví dụ khác) methcallđiểm chuẩn được sử dụng trong mục blog trong liên kết cuối cùng của bạn. Mặc dù tên (và mọi thứ thậm chí có thể trông như thế nào), phiên bản C ++ này không thực sự đo lường nhiều về chi phí cuộc gọi phương thức. Phần mã hóa ra rất quan trọng là trong lớp Toggle:

class Toggle {
public:
    Toggle(bool start_state) : state(start_state) { }
    virtual ~Toggle() {  }
    bool value() {
        return(state);
    }
    virtual Toggle& activate() {
        state = !state;
        return(*this);
    }
    bool state;
};

Phần quan trọng hóa ra là state = !state;. Hãy xem xét những gì xảy ra khi chúng ta thay đổi mã để mã hóa trạng thái intthay vì bool:

class Toggle {
    enum names{ bfalse = -1, btrue = 1};
    const static names values[2];
    int state;

public:
    Toggle(bool start_state) : state(values[start_state]) 
    { }
    virtual ~Toggle() {  }
    bool value() {  return state==btrue;    }

    virtual Toggle& activate() {
        state = -state;
        return(*this);
    }
};

Thay đổi nhỏ này cải thiện tốc độ tổng thể khoảng 5: 1 . Mặc dù điểm chuẩn được dự định để đo thời gian gọi phương thức, nhưng thực tế hầu hết những gì nó đo được là thời gian để chuyển đổi giữa intbool. Tôi chắc chắn đồng ý rằng sự kém hiệu quả được hiển thị bởi bản gốc là không may - nhưng do hiếm khi nó xuất hiện trong mã thực và sự dễ dàng có thể được khắc phục khi / nếu nó phát sinh, tôi có một thời gian khó khăn để suy nghĩ Nó có ý nghĩa nhiều.

Trong trường hợp bất kỳ ai quyết định chạy lại các điểm chuẩn liên quan, tôi cũng nên nói thêm rằng có một sửa đổi gần như tầm thường đối với phiên bản Java tạo ra (hoặc ít nhất một lần được tạo ra - Tôi đã không chạy lại các thử nghiệm với JVM gần đây để xác nhận họ vẫn làm) một cải tiến khá đáng kể trong phiên bản Java. Phiên bản Java có NthToggle :: activ () trông như thế này:

public Toggle activate() {
this.counter += 1;
if (this.counter >= this.count_max) {
    this.state = !this.state;
    this.counter = 0;
}
return(this);
}

Thay đổi điều này để gọi hàm cơ bản thay vì thao tác this.statetrực tiếp giúp cải thiện tốc độ đáng kể (mặc dù không đủ để theo kịp phiên bản C ++ đã sửa đổi).

Vì vậy, những gì chúng tôi kết thúc là một giả định sai về mã byte được giải thích so với một số điểm chuẩn tồi tệ nhất (tôi) từng thấy. Không phải là đưa ra một kết quả có ý nghĩa.

Kinh nghiệm của riêng tôi là với các lập trình viên có kinh nghiệm như nhau, chú ý đến việc tối ưu hóa như nhau, C ++ sẽ đánh bại Java thường xuyên hơn không - nhưng (ít nhất là giữa hai điều này), ngôn ngữ sẽ hiếm khi tạo ra sự khác biệt nhiều như các lập trình viên và thiết kế. Các điểm chuẩn được trích dẫn cho chúng tôi biết nhiều hơn về năng lực (trong) / (không) trung thực của các tác giả của họ so với các ngôn ngữ mà họ hướng đến điểm chuẩn.

[Chỉnh sửa: Như được ngụ ý ở một nơi ở trên nhưng không bao giờ được tuyên bố trực tiếp như tôi có thể có, kết quả tôi trích dẫn là những gì tôi đã nhận được khi thử nghiệm điều này ~ 5 năm trước, sử dụng các triển khai C ++ và Java hiện tại vào thời điểm đó . Tôi đã không chạy lại các bài kiểm tra với các triển khai hiện tại. Tuy nhiên, nhìn thoáng qua cho thấy mã chưa được sửa, vì vậy tất cả những gì đã thay đổi sẽ là khả năng của trình biên dịch để che giấu các vấn đề trong mã.]

Nếu chúng ta bỏ qua những ví dụ Java, tuy nhiên, nó thực sự có thể giải thích cho mã để chạy nhanh hơn so với mã biên dịch (mặc dù khó khăn và hơi bất thường).

Cách thông thường này xảy ra là mã được diễn giải nhỏ gọn hơn nhiều so với mã máy hoặc nó đang chạy trên CPU có bộ đệm dữ liệu lớn hơn bộ đệm mã.

Trong trường hợp như vậy, một trình thông dịch nhỏ (ví dụ: trình thông dịch bên trong của triển khai Forth) có thể hoàn toàn phù hợp với bộ đệm mã và chương trình phiên dịch phù hợp hoàn toàn với bộ đệm dữ liệu. Bộ nhớ cache thường nhanh hơn bộ nhớ chính theo hệ số ít nhất là 10 và thường là nhiều hơn (hệ số 100 không đặc biệt hiếm gặp nữa).

Vì vậy, nếu bộ đệm nhanh hơn bộ nhớ chính theo hệ số N và cần ít hơn hướng dẫn mã máy N để thực hiện từng mã byte, mã byte sẽ giành chiến thắng (Tôi đơn giản hóa, nhưng tôi nghĩ rằng ý tưởng chung vẫn nên được rõ ràng).


26
+1, ack đầy đủ. Đặc biệt là "ngôn ngữ sẽ hiếm khi tạo ra sự khác biệt nhiều như các lập trình viên và thiết kế" - bạn sẽ thường vấp ngã về các vấn đề mà bạn có thể tối ưu hóa thuật toán, ví dụ cải thiện big-O sẽ giúp tăng cường hơn nhiều so với trình biên dịch tốt nhất có thể.
schnaader

1
"Trong trường hợp bất kỳ ai quyết định chạy lại các điểm chuẩn liên quan ..." ĐỪNG! Trở lại năm 2005, những nhiệm vụ cũ đó đã bị loại bỏ và được thay thế bằng các nhiệm vụ hiện được hiển thị trong trò chơi điểm chuẩn. Nếu bất cứ ai muốn chạy lại một số chương trình thì vui lòng chạy lại các chương trình hiện tại cho các nhiệm vụ hiện tại được hiển thị trên trang chủ trò chơi điểm chuẩn bắn
ra.alioth.debian.org

@igouy: Một số người có thể chỉ muốn xác nhận / từ chối kết quả từ điểm chuẩn họ đã chạy, với mức tối thiểu cần sửa để ít nhất cung cấp cho họ một số mối quan hệ tối thiểu với thực tế. Đồng thời, về cơ bản, bạn đã đúng: các điểm chuẩn trong câu hỏi rất tệ đến nỗi chỉ cần sửa các lỗi rõ ràng nhất sẽ không giúp được gì nhiều.
Jerry Coffin

Và đó là lý do tại sao, vào năm 2005, chúng đã bị loại bỏ và được thay thế bởi các nhiệm vụ hiện được thể hiện trong trò chơi điểm chuẩn. Những người không biết nên chạy lại những chương trình cũ đó.
igouy

13
+1 Tôi không thích mọi người mã hóa C ++ theo kiểu C hoặc Java và sau đó nêu Java là vượt trội. từ chối trách nhiệm: Tôi không gọi bất kỳ ngôn ngữ nào vượt trội, nhưng viết mã C ++ nhảm nhí theo phong cách có thể hoàn toàn phù hợp với ngôn ngữ khác không làm cho cả hai ngôn ngữ có thể so sánh được.
Christian Rau

111

C / C ++ được thực hiện bởi một chuyên gia với thời gian không giới hạn sẽ ít nhất là nhanh hoặc nhanh hơn Java. Cuối cùng, bản thân Java được viết bằng C / C ++, do đó bạn tất nhiên có thể làm mọi thứ mà Java làm nếu bạn sẵn sàng bỏ ra đủ nỗ lực kỹ thuật.

Tuy nhiên, trong thực tế, Java thường thực thi rất nhanh vì những lý do sau:

  • Trình biên dịch JIT - mặc dù các lớp Java được lưu trữ dưới dạng mã byte, nhưng điều này (thường) được biên dịch thành mã gốc bởi trình biên dịch JIT khi chương trình khởi động. Sau khi được biên dịch, nó là mã gốc thuần túy - vì vậy về mặt lý thuyết, nó có thể được thực hiện cũng như được biên dịch C / C ++ một khi chương trình đã chạy đủ lâu (tức là sau khi tất cả quá trình biên dịch JIT đã được thực hiện)
  • Bộ sưu tập rác trong Java cực kỳ nhanh chóng và hiệu quả - Hotspot GC có lẽ là triển khai GC toàn diện tốt nhất trên thế giới. Đó là kết quả của nhiều năm nỗ lực chuyên môn của Sun và các công ty khác. Khá nhiều hệ thống quản lý bộ nhớ phức tạp mà bạn tự cuộn trong C / C ++ sẽ tệ hơn. Tất nhiên bạn có thể viết các sơ đồ quản lý bộ nhớ cơ bản khá nhanh / nhẹ trong C / C ++, nhưng chúng sẽ không linh hoạt như một hệ thống GC đầy đủ. Do hầu hết các hệ thống hiện đại cần quản lý bộ nhớ phức tạp, do đó Java có lợi thế lớn cho các tình huống trong thế giới thực.
  • Nhắm mục tiêu nền tảng tốt hơn - bằng cách trì hoãn biên dịch để khởi động ứng dụng (biên dịch JIT, v.v.), trình biên dịch Java có thể tận dụng thực tế là nó biết bộ xử lý chính xác mà nó đang thực thi. Điều này có thể cho phép một số tối ưu hóa rất có lợi mà bạn sẽ không thể thực hiện được trong mã C / C ++ được biên dịch trước cần nhắm mục tiêu tập lệnh xử lý "mẫu số chung thấp nhất".
  • Thống kê thời gian chạy - vì quá trình biên dịch JIT được thực hiện trong thời gian chạy, nó có thể thu thập số liệu thống kê trong khi chương trình đang thực thi cho phép tối ưu hóa tốt hơn (ví dụ: biết xác suất mà một nhánh cụ thể được thực hiện). Điều này có thể cho phép các trình biên dịch Java JIT tạo ra mã tốt hơn các trình biên dịch C / C ++ (phải "đoán" nhánh có khả năng nhất trước, một giả định thường có thể sai).
  • Các thư viện rất tốt - thời gian chạy Java chứa một loạt các thư viện được viết rất tốt với hiệu năng tốt (đặc biệt là cho các ứng dụng phía máy chủ). Thường thì những thứ này tốt hơn bạn có thể tự viết hoặc lấy dễ dàng cho C / C ++.

Đồng thời C / C ++ cũng có một số ưu điểm:

  • Có thêm thời gian để thực hiện tối ưu hóa nâng cao - Quá trình biên dịch C / C ++ được thực hiện một lần và do đó có thể dành thời gian đáng kể để thực hiện tối ưu hóa nâng cao nếu bạn định cấu hình để thực hiện. Không có lý do lý thuyết nào khiến Java không thể làm như vậy, nhưng trong thực tế, bạn muốn Java biên dịch mã JIT tương đối nhanh, do đó trình biên dịch JIT có xu hướng tập trung vào các tối ưu hóa "đơn giản" hơn.
  • Các hướng dẫn không thể biểu thị bằng mã byte - trong khi mã byte Java hoàn toàn có mục đích chung, vẫn có một số điều bạn có thể làm ở mức độ thấp mà bạn không thể thực hiện trong mã byte (số học con trỏ không được kiểm tra là một ví dụ hay!). Bằng cách (ab) sử dụng các loại thủ thuật này, bạn có thể nhận được một số lợi thế về hiệu suất
  • Các ràng buộc "an toàn" ít hơn - Java thực hiện một số công việc bổ sung để đảm bảo rằng các chương trình an toàn và đáng tin cậy. Ví dụ là kiểm tra giới hạn trên mảng, đảm bảo đồng thời nhất định, kiểm tra con trỏ null, nhập an toàn trên phôi, v.v. Bằng cách tránh những điều này trong C / C ++, bạn có thể nhận được một số hiệu suất tăng (mặc dù có thể cho rằng đây có thể là một ý tưởng tồi!)

Tổng thể, nói chung:

  • Java và C / C ++ có thể đạt được tốc độ tương tự
  • C / C ++ có thể có lợi thế không đáng kể trong hoàn cảnh khắc nghiệt (chẳng có gì đáng ngạc nhiên khi các nhà phát triển trò chơi AAA vẫn thích nó chẳng hạn)
  • Trong thực tế, nó sẽ phụ thuộc vào cách các yếu tố khác nhau được liệt kê ở trên cân bằng cho ứng dụng cụ thể của bạn.

9
Quảng cáo "có nhiều thời gian hơn để tối ưu hóa trong C ++": Đó là một trong những điều chỉnh mà Oracle VM thực hiện khi bạn chọn Server VM: Nó chấp nhận chi phí khởi động cao hơn để cho phép hiệu suất cao hơn trong thời gian dài. Máy khách VM, tuy nhiên được điều chỉnh cho thời gian khởi động tối ưu. Vì vậy, sự khác biệt đó thậm chí tồn tại trong Java.
Joachim Sauer

8
-1: Trình biên dịch C ++ có thể mất nhiều thời gian hơn (giờ, theo nghĩa đen, đối với một thư viện lớn) để tạo ra một nhị phân rất tối ưu. Trình biên dịch Java JIT không thể mất quá nhiều thời gian, ngay cả phiên bản "máy chủ". Tôi thực sự nghi ngờ rằng trình biên dịch Java JIT có thể thực hiện Tối ưu hóa toàn bộ chương trình theo cách mà trình biên dịch MS C ++ thực hiện.
quant_dev

20
@quant_dev: chắc chắn, nhưng đó không phải là chính xác những gì tôi đã nói trong câu trả lời của tôi như là một lợi thế của C ++ (có thêm thời gian để thực hiện tối ưu hóa nâng cao)? Vậy tại sao -1?
mikera

13
Thu gom rác không phải là một lợi thế về tốc độ cho Java. Đó chỉ là một lợi thế về tốc độ nếu bạn là một lập trình viên C ++ không biết bạn đang làm gì. Nếu tất cả những gì bạn đang kiểm tra là bạn có thể phân bổ nhanh như thế nào, thì có, người thu gom rác sẽ giành chiến thắng. Tuy nhiên, hiệu suất chương trình tổng thể vẫn có thể được thực hiện tốt hơn bằng cách quản lý bộ nhớ thủ công.
Billy ONeal

4
... Nhưng với C ++, về mặt lý thuyết, bạn luôn có thể đặt một "lớp giống như JIT" để tối ưu hóa chi nhánh tương tự trong thời gian chạy, trong khi vẫn duy trì tốc độ thô của chương trình C ++. (Về mặt lý thuyết. :()
Mateen Ulhaq

19

Thời gian chạy Java không diễn giải mã byte. Thay vào đó, nó sử dụng cái được gọi là Just In Time Compilation . Về cơ bản, khi chương trình được chạy, nó sẽ sử dụng mã byte và chuyển đổi nó thành mã gốc được tối ưu hóa cho CPU cụ thể.


Trong thực tế, có. Về nguyên tắc, điều này phụ thuộc - các máy ảo Java đời đầu được sử dụng các trình thông dịch mã byte và bạn vẫn có thể tìm thấy các máy ảo phiên dịch mã byte nếu bạn thấy đủ cứng.
Steve314

10
@ Steve314: nhưng các máy ảo thông dịch hoàn toàn sẽ không phải là máy ảo vượt trội hơn C ++, vì vậy chúng không thực sự phù hợp với câu hỏi này.
Joachim Sauer

Trình biên dịch JIT cũng có thể tối ưu hóa linh hoạt cho việc sử dụng mã cụ thể, điều này là không thể đối với mã được biên dịch tĩnh.
starblue

2
@starblue, tốt, phần nào có thể với một trình biên dịch tĩnh - xem tối ưu hóa hướng dẫn hồ sơ.
SK-logic

18

Tất cả mọi thứ đều bình đẳng, bạn có thể nói: không, Java không bao giờ nên nhanh hơn . Bạn luôn có thể triển khai Java trong C ++ từ đầu và nhờ đó có hiệu suất tốt nhất. Trong thực tế, tuy nhiên:

  • JIT biên dịch mã trên máy của người dùng cuối, cho phép nó tối ưu hóa cho CPU chính xác mà họ đang chạy. Mặc dù có một chi phí ở đây để biên dịch, nhưng nó cũng có thể trả hết cho các ứng dụng chuyên sâu. Thông thường các chương trình thực tế không được biên dịch cho CPU bạn đang sử dụng.
  • Trình biên dịch Java có thể tốt hơn trong việc tự động tối ưu hóa mọi thứ so với trình biên dịch C ++. Hoặc có thể không, nhưng trong thế giới thực, mọi thứ không phải lúc nào cũng hoàn hảo.
  • Hành vi hiệu suất có thể thay đổi do các yếu tố khác, chẳng hạn như thu gom rác. Trong C ++, bạn thường gọi hàm hủy ngay lập tức khi thực hiện với một đối tượng. Trong Java, bạn chỉ cần phát hành tham chiếu, trì hoãn việc hủy thực tế. Đây là một ví dụ khác về sự khác biệt không có ở đây cũng như ở đó, về hiệu suất. Tất nhiên, bạn có thể lập luận rằng bạn có thể triển khai GC trong C ++ và được thực hiện với nó, nhưng thực tế là rất ít người làm / muốn / có thể.

Ở một bên, điều này làm tôi nhớ đến cuộc tranh luận về C trong thập niên 80/90. Mọi người đều tự hỏi "liệu C có thể nhanh như lắp ráp không?". Về cơ bản, câu trả lời là: không có trên giấy, nhưng trong thực tế, trình biên dịch C đã tạo ra mã hiệu quả hơn 90% các lập trình viên lắp ráp (tốt, một khi nó đã trưởng thành một chút).


2
Về GC, không chỉ là GC có thể trì hoãn việc phá hủy các vật thể (điều không nên quan trọng trong thời gian dài hơn); thực tế là với các GC hiện đại, việc phân bổ / phân bổ các đối tượng tồn tại trong thời gian ngắn là cực kỳ rẻ so với C ++.
Péter Török

@ PéterTörök vâng, bạn nói đúng, điểm tốt.
Daniel B

9
@ PéterTörök Nhưng trong C ++, các đối tượng có thời gian tồn tại ngắn thường được đặt trên ngăn xếp, do đó nhanh hơn nhiều so với bất kỳ heap nào của Java-ed có thể sử dụng.
quant_dev

@quant_dev, bạn đã quên một hiệu ứng GC quan trọng khác: nén. Vì vậy, tôi sẽ không chắc chắn cách nào nhanh hơn.
SK-logic

3
@DonalFellows Điều gì khiến bạn nghĩ rằng tôi phải lo lắng về việc quản lý bộ nhớ trong C ++? Hầu hết thời gian tôi không. Có những mẫu đơn giản bạn cần áp dụng, khác với Java, nhưng đó là nó.
quant_dev

10

Nhưng phân bổ chỉ là một nửa của quản lý bộ nhớ - phân bổ là nửa còn lại. Nó chỉ ra rằng đối với hầu hết các đối tượng, chi phí thu gom rác trực tiếp là - không. Điều này là do một bộ sưu tập sao chép không cần phải truy cập hoặc sao chép các đối tượng đã chết, chỉ có các đối tượng sống. Vì vậy, các đối tượng trở thành rác ngay sau khi phân bổ không đóng góp khối lượng công việc cho chu trình thu thập.

...

Các JVM rất tốt trong việc tìm ra những thứ mà chúng ta từng cho rằng chỉ có nhà phát triển mới có thể biết. Bằng cách để JVM chọn giữa phân bổ ngăn xếp và phân bổ heap trên cơ sở từng trường hợp cụ thể, chúng ta có thể nhận được các lợi ích hiệu năng của phân bổ ngăn xếp mà không khiến lập trình viên thống nhất về việc phân bổ trên ngăn xếp hay trên heap.

http://www.ibm.com/developerworks/java/l Library / j-jtp09275 / index.html


Đây chỉ là một phần nhỏ của toàn bộ bức tranh, nhưng dù sao cũng khá liên quan.
Joachim Sauer

2
Tôi thích cách thức của điều này là: java dành cho noobs, tin tưởng vào phép thuật GC, nó biết rõ hơn.
Mẹ ơi.

1
@Morg: Hoặc bạn có thể đọc theo cách đó: Java dành cho những người thích hoàn thành công việc thay vì lãng phí thời gian của họ với việc quản lý bộ nhớ thủ công và xử lý bộ nhớ bit.
Landei

4
@Landei Tôi nghĩ rằng nhận xét của bạn sẽ có độ tin cậy cao hơn nếu bất kỳ cơ sở mã được sử dụng rộng rãi lâu dài nào được viết bằng Java. Trong thế giới của tôi, các hệ điều hành thực sự được viết bằng C, postgreSQL được viết bằng C, là những công cụ quan trọng nhất thực sự sẽ gây khó khăn khi viết lại. Java là (và thậm chí là phiên bản chính thức) để cho phép những người ít kỹ năng hơn lập trình theo bầy đàn và đạt được kết quả rõ ràng.
Mẹ ơi.

1
@Morg Tôi thấy rất lạ khi bạn dường như chỉ tập trung vào HĐH. Điều này chỉ đơn giản là không thể là một biện pháp tốt, vì nhiều lý do. Thứ nhất, các yêu cầu của HĐH khác biệt lớn so với hầu hết các phần mềm khác, thứ hai bạn có nguyên tắc ngón tay cái Panda (ai muốn viết lại một HĐH hoàn chỉnh bằng ngôn ngữ khác, ai muốn viết HĐH của riêng mình nếu có hoạt động và thậm chí là các lựa chọn thay thế miễn phí?) và thứ ba phần mềm khác sử dụng các tính năng của HĐH, do đó không cần phải viết trình điều khiển đĩa, trình quản lý tác vụ, v.v. Nếu bạn không thể cung cấp một số đối số tốt hơn (không hoàn toàn dựa trên HĐH), bạn nghe có vẻ đáng ghét.
Landei

5

Mặc dù một chương trình Java được tối ưu hóa hoàn toàn sẽ hiếm khi đánh bại một chương trình C ++ được tối ưu hóa hoàn toàn, nhưng sự khác biệt trong những thứ như quản lý bộ nhớ có thể tạo ra nhiều thuật toán được triển khai một cách tự nhiên trong Java nhanh hơn các thuật toán tương tự được triển khai trong C ++.

Như @Jerry Coffin đã chỉ ra, có rất nhiều trường hợp những thay đổi đơn giản có thể làm cho mã nhanh hơn nhiều - nhưng thường thì nó có thể mất quá nhiều điều chỉnh ô uế trong một ngôn ngữ này hoặc ngôn ngữ khác để cải thiện hiệu suất đáng giá. Đó có lẽ là những gì bạn thấy trong một điểm chuẩn tốt cho thấy Java hoạt động tốt hơn C ++.

Ngoài ra, mặc dù thường không đáng kể, nhưng có một số tối ưu hóa hiệu suất mà ngôn ngữ JIT như Java có thể làm được mà C ++ không thể. Thời gian chạy Java có thể bao gồm các cải tiến sau khi mã được biên dịch, điều đó có nghĩa là JIT có khả năng tạo mã được tối ưu hóa để tận dụng các tính năng CPU mới (hoặc ít nhất là khác nhau). Vì lý do này, một nhị phân Java 10 năm tuổi có thể có khả năng vượt trội hơn so với nhị phân C ++ 10 tuổi.

Cuối cùng, an toàn loại hoàn toàn trong bức tranh lớn hơn, trong những trường hợp rất hiếm, có thể cải thiện hiệu suất cực cao. Singularity , một hệ điều hành thử nghiệm được viết gần như hoàn toàn bằng ngôn ngữ dựa trên C #, có khả năng giao tiếp và đa nhiệm nhanh hơn nhiều do thực tế là không cần ranh giới quá trình phần cứng hoặc chuyển đổi ngữ cảnh đắt tiền.


5

Đăng bởi Tim Holloway trên JavaRanch:

Đây là một ví dụ nguyên thủy: Quay lại khi các máy hoạt động theo chu kỳ xác định theo toán học, một lệnh rẽ nhánh thường có 2 thời gian khác nhau. Một cho khi chi nhánh được thực hiện, một cho khi chi nhánh không được thực hiện. Thông thường, trường hợp không có chi nhánh là nhanh hơn. Rõ ràng, điều này có nghĩa là bạn có thể tối ưu hóa logic dựa trên kiến ​​thức về trường hợp nào phổ biến hơn (chịu sự ràng buộc mà những gì chúng ta "biết" không phải luôn luôn là trường hợp thực sự).

Biên dịch lại JIT tiến thêm một bước này. Nó theo dõi việc sử dụng thời gian thực thực tế và lật logic dựa trên những gì thực sự là trường hợp phổ biến nhất. Và lật nó lại một lần nữa nếu khối lượng công việc thay đổi. Mã được biên dịch tĩnh không thể làm điều này. Đó là cách Java đôi khi có thể thực hiện mã lắp ráp / mã C / C ++ được điều chỉnh bằng tay.

Nguồn: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time


3
Và một lần nữa, điều này là sai / không đầy đủ. Trình biên dịch tĩnh với tùy chọn hướng dẫn hồ sơ có thể nhận ra điều này.
Konrad Rudolph

2
Konrad, trình biên dịch tĩnh có thể lật logic dựa trên khối lượng công việc hiện tại? Theo tôi hiểu, trình biên dịch tĩnh tạo mã một lần và nó sẽ giữ nguyên như vậy mãi mãi.
Thiago Negri

2
Khối lượng công việc hiện tại, không. Nhưng khối lượng công việc điển hình . Tối ưu hóa theo hướng dẫn hồ sơ sẽ phân tích cách chương trình của bạn chạy dưới tải thông thường và tối ưu hóa các điểm nóng tương ứng, giống như HotSpot JIT.
Konrad Rudolph

4

Đó là bởi vì bước cuối cùng tạo mã máy xảy ra bên trong JVM khi chạy chương trình Java của bạn, thay vì rõ ràng khi xây dựng proram C ++ của bạn.

Bạn nên xem xét thực tế rằng các JVM hiện đại dành khá nhiều thời gian để biên dịch mã byte khi đang bay sang mã máy gốc để làm cho nó nhanh nhất có thể. Điều này cho phép JVM thực hiện tất cả các loại thủ thuật trình biên dịch thậm chí có thể tốt hơn bằng cách biết dữ liệu lược tả của chương trình đang được chạy.

Chỉ là một thứ như tự động nội tuyến một getter, do đó không cần phải có JUMP-RETURN để có được một giá trị, tăng tốc mọi thứ.

Tuy nhiên, điều thực sự đã cho phép các chương trình nhanh là làm sạch tốt hơn sau đó. Cơ chế thu gom rác trong Java nhanh hơn so với không có malloc thủ công trong C. Nhiều triển khai không có malloc hiện đại sử dụng trình thu gom rác bên dưới.


Lưu ý rằng công cụ nhúng này làm cho việc bắt đầu JVM lớn hơn và chậm hơn cho đến khi mã tốt hơn có cơ hội bắt kịp.

1
"Nhiều triển khai không có malloc hiện đại sử dụng một bộ thu gom rác bên dưới." Có thật không? Tôi muốn biết thêm; Bạn có lời khuyên nào chưa?
Sean McMillan

Cảm ơn bạn. Tôi đã cố gắng tìm một cách để nói rằng JVM không còn chứa đơn giản là trình biên dịch đúng lúc biên dịch thành mã thực thi, mà là trình biên dịch điểm nóng cấu hình mã đang chạy và tối ưu hóa hơn nữa. Tôi trình biên dịch một lần như C ++ đấu tranh để phù hợp với điều đó.
Cao nguyên Mark

@SeanMcMillan, tôi đã thấy một phân tích trước đây về hiệu suất của việc triển khai không có malloc trong đó người ta đã đề cập rằng người nhanh nhất đã sử dụng một công cụ thu gom rác bên dưới. Tôi không thể nhớ nơi tôi đọc nó.

Có phải đó là GC bảo thủ của BDW?
Demi

4

Câu trả lời ngắn gọn - không phải vậy. Quên đi, chủ đề xưa như lửa hay bánh xe. Java hoặc .NET không và sẽ không nhanh hơn C / C ++. Nó đủ nhanh cho hầu hết các nhiệm vụ mà bạn không cần phải suy nghĩ về tối ưu hóa. Giống như các biểu mẫu và xử lý SQL, nhưng đó là nơi nó kết thúc.

Đối với điểm chuẩn, hoặc các ứng dụng nhỏ được viết bởi các nhà phát triển không đủ năng lực, kết quả cuối cùng sẽ là Java / .NET có thể sẽ bị đóng và thậm chí có thể nhanh hơn.

Trong thực tế, những việc đơn giản như phân bổ bộ nhớ trên stack hoặc đơn giản là sử dụng memzones sẽ đơn giản giết chết Java / .NET ngay tại chỗ.

Rác thu thập thế giới đang sử dụng loại memzone với tất cả các kế toán. Thêm memzone vào C và C sẽ nhanh hơn ngay tại chỗ. Đặc biệt đối với các điểm chuẩn Java mã C "mã hiệu suất cao", giống như sau:

for(...)
{
alloc_memory//Allocating heap in a loop is verrry good, in't it?
zero_memory//Extra zeroing, we really need it in our performance code
do_stuff//something like memory[i]++
realloc//This is lovely speedup
strlen//loop through all memory, because storing string length is soo getting old
free//Java will do that outside out timing loop, but oh well, we're comparing apples to oranges here
}//loop 100000 times

Hãy thử sử dụng các biến dựa trên ngăn xếp trong C / C ++ (hoặc vị trí mới), chúng dịch sang sub esp, 0xff, đó là một lệnh x86 duy nhất, đánh bại điều đó với Java - bạn không thể ...

Hầu hết thời gian tôi thấy những chiếc ghế dài mà Java so với C ++ được so sánh, nó khiến tôi đi như thế nào, wth? Chiến lược phân bổ bộ nhớ sai, các thùng chứa tự phát triển mà không có dự trữ, nhiều cái mới. Điều này thậm chí không gần với mã C / C ++ định hướng hiệu suất.

Cũng là một bài đọc tốt: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf


1
Sai lầm. Hoàn toàn sai. Bạn sẽ không thể làm tốt hơn một GC thu gọn với quản lý bộ nhớ thủ công của bạn. Việc đếm tham chiếu ngây thơ sẽ không bao giờ tốt hơn một dấu hiệu thích hợp. Ngay khi nói đến việc quản lý bộ nhớ phức tạp, C ++ là một sự chậm trễ.
SK-logic

3
@ SK-Logic: Sai, với memzones hoặc phân bổ ngăn xếp KHÔNG có phân bổ bộ nhớ hoặc phân bổ bộ nhớ TẠI TẤT CẢ. Bạn có một khối bộ nhớ và bạn chỉ cần viết cho nó. Đánh dấu khối là miễn phí với biến dễ bay hơi như bảo vệ đồng thời InterlockedExchange, v.v., và luồng tiếp theo chỉ đưa dữ liệu của nó vào khối preallocated mà không đi đến hệ điều hành cho bộ nhớ, nếu nó thấy nó miễn phí. Với ngăn xếp, điều đó thậm chí còn dễ dàng hơn, với ngoại lệ duy nhất là bạn không thể kết xuất 50 MB trên ngăn xếp. Và thời gian tồn tại của đối tượng chỉ ở bên trong {}.
Coder

2
@ SK-logic: Trình biên dịch là chính xác trước, hiệu suất thứ hai. Công cụ tìm kiếm, công cụ cơ sở dữ liệu, hệ thống giao dịch thời gian thực, trò chơi là những gì tôi sẽ coi hiệu suất là quan trọng. Và hầu hết những người dựa vào cấu trúc phẳng. Và dù sao đi nữa, trình biên dịch hầu hết được viết bằng C / C ++. Với phân bổ tùy chỉnh tôi đoán. Sau đó, một lần nữa, tôi thấy không có vấn đề gì với việc sử dụng các phần tử cây hoặc danh sách trên rammap. Bạn chỉ cần sử dụng vị trí mới. Không có nhiều phức tạp trong đó.
Coder

3
@ SK-logic: Nó không nhanh hơn nhiều, mọi ứng dụng .NET / Java mà tôi đã thấy, luôn trở nên chậm hơn và là một con heo thực sự. Mỗi lần viết lại ứng dụng được quản lý thành mã SANE C / C ++ dẫn đến ứng dụng sạch hơn và nhẹ hơn. Các ứng dụng được quản lý luôn nặng. Xem VS2010 so với năm 2008 Cấu trúc dữ liệu tương tự, nhưng VS2010 là HOG. Các ứng dụng C / C ++ được viết chính xác thường khởi động trong một phần nghìn giây và không bị kẹt trên màn hình giật gân, đồng thời tiêu tốn ít bộ nhớ hơn. Nhược điểm duy nhất là bạn phải mã hóa phần cứng và rất nhiều người không biết nó hiện nay như thế nào. Đó chỉ là điểm chuẩn nơi quản lý có cơ hội.
Coder

2
bằng chứng giai thoại của bạn không được tính. Điểm chuẩn thích hợp cho thấy sự khác biệt thực sự. Điều đặc biệt lạ là bạn đang đề cập đến các ứng dụng GUI, bị ràng buộc với các thư viện GUI cồng kềnh và tối ưu. Và, điều quan trọng hơn - về mặt lý thuyết, giới hạn hiệu suất cao hơn nhiều đối với một GC được thực hiện đúng.
SK-logic

2

Thực tế là cả hai chỉ là các trình biên dịch cấp cao thực hiện chính xác những gì lập trình viên nói với họ, ví dụ như cách lập trình viên bảo họ theo thứ tự chính xác mà lập trình viên nói với họ. Sự khác biệt hiệu suất là rất nhỏ đến mức không phù hợp với tất cả các mục đích thực tế.

Ngôn ngữ không "chậm", lập trình viên đã viết một chương trình chậm. Rất hiếm khi một chương trình viết theo cách tốt nhất bằng một ngôn ngữ (đối với bất kỳ mục đích thực tế nào), một chương trình làm điều tương tự bằng cách sử dụng cách tốt nhất của ngôn ngữ thay thế, trừ khi tác giả của nghiên cứu ra để mài rìu cụ thể của mình.

Rõ ràng nếu bạn đang đi đến một trường hợp cạnh hiếm như các hệ thống nhúng thời gian thực cứng, sự lựa chọn ngôn ngữ có thể tạo ra sự khác biệt, nhưng trường hợp này có thường xuyên không? và trong những trường hợp đó, mức độ thường xuyên là sự lựa chọn chính xác không mù quáng rõ ràng.


2
Về lý thuyết, một máy ảo JITting "lý tưởng" phải vượt trội hơn so với mã được biên dịch tĩnh, bằng cách điều chỉnh tối ưu hóa của nó với thông tin lược tả được thu thập động. Trong thực tế, trình biên dịch JIT chưa thông minh lắm, nhưng ít nhất chúng có khả năng tạo ra một mã có chất lượng tương tự như với các đồng nghiệp tĩnh lớn hơn và chậm hơn.
SK-logic

2

Xem các liên kết sau ... Nhưng làm thế nào điều này thậm chí có thể? Nó làm tôi suy nghĩ rằng mã byte được giải thích có thể nhanh hơn ngôn ngữ được biên dịch.

  1. Những bài đăng trên blog cung cấp bằng chứng đáng tin cậy?
  2. Những bài đăng trên blog cung cấp bằng chứng dứt khoát?
  3. Những bài đăng trên blog thậm chí còn cung cấp bằng chứng về "mã byte được giải thích"?

Keith Lea nói với bạn rằng có "lỗ hổng rõ ràng" nhưng không làm gì với "lỗ hổng rõ ràng" đó. Trở lại năm 2005, những nhiệm vụ cũ đó đã bị loại bỏ và được thay thế bằng các nhiệm vụ hiện được hiển thị trong trò chơi điểm chuẩn .

Keith Lea nói với bạn rằng anh ta "đã lấy mã điểm chuẩn cho C ++ và Java từ Trò chơi bắn súng ngôn ngữ máy tính lớn đã lỗi thời và thực hiện các bài kiểm tra" nhưng thực tế anh ta chỉ hiển thị các phép đo cho 14 trong số 25 bài kiểm tra lỗi thời đó .

Keith Lea bây giờ nói với bạn rằng anh ta đã không cố chứng minh bất cứ điều gì với bài đăng trên blog bảy năm trước, nhưng sau đó anh ta nói "Tôi phát ốm khi nghe người ta nói Java chậm, khi tôi biết nó khá nhanh ..." hồi đó có một cái gì đó anh đang cố chứng minh.

Christian Felde nói với bạn "Tôi không tạo mã, chỉ chạy lại các bài kiểm tra." như thể điều đó đã loại bỏ anh ta khỏi mọi trách nhiệm đối với quyết định công khai các phép đo của các nhiệm vụ và chương trình mà Keith Lea đã chọn.

Các phép đo của 25 chương trình nhỏ xíu có cung cấp bằng chứng rõ ràng không?

Các phép đo này dành cho các chương trình chạy dưới dạng Java "chế độ hỗn hợp" không hiểu Java - "Hãy nhớ cách HotSpot hoạt động." Bạn có thể dễ dàng tìm hiểu Java chạy "mã byte được giải thích" tốt như thế nào, bởi vì bạn có thể buộc Java chỉ giải thích mã byte - đơn giản là thời gian một số chương trình Java chạy cùng và không có tùy chọn -Xint.


-1

Điều đó làm tôi ngạc nhiên về mức độ phổ biến của khái niệm kỳ lạ về "mã byte được giải thích" này. Bạn đã bao giờ mọi người nghe nói về việc biên soạn JIT chưa? Đối số của bạn không thể được áp dụng cho Java.

Nhưng, để JVM sang một bên, có những trường hợp khi một mã luồng trực tiếp hoặc thậm chí là một diễn giải mã byte tầm thường có thể dễ dàng vượt trội hơn một mã gốc được tối ưu hóa mạnh mẽ. Giải thích khá đơn giản: mã byte có thể khá nhỏ gọn và sẽ phù hợp với bộ đệm nhỏ của bạn khi một phiên bản mã gốc của cùng một thuật toán sẽ có một vài lỗi bộ nhớ cache cho một lần lặp.


Tính phổ biến của việc giải thích có lẽ là do những người thành thạo trong khoa học máy tính của họ. Máy ảo java là một máy chấp nhận mã byte java và chạy nó trên máy / không / có khả năng chạy mã byte java nguyên bản, mà không có khả năng viết chương trình gốc tương đương về chức năng. Ergo nó là một thông dịch viên. Bạn có thể cung cấp cho các kỹ thuật bộ nhớ đệm của nó bất kỳ tên nào bạn có thể nghĩ ra, JIT hoặc cách khác, nhưng nó là một trình thông dịch theo định nghĩa của trình thông dịch.
thiton

@thiton, rất có thể CS-fu của bạn hơi yếu. JVM không thực hiện bất kỳ loại giải thích nào (đối với các điểm nóng) - như một người dám đề cập đến CS, bạn phải biết ý nghĩa của nó và ngữ nghĩa hoạt động của một diễn giải khác với việc chạy mã gốc như thế nào. Nhưng, rất có thể, đơn giản là bạn không biết đủ CS để phân biệt việc biên dịch với diễn giải.
SK-logic

2
Umm, nhưng mã byte, để được chạy, phải được chuyển đổi thành mã gốc - bạn không thể cung cấp mã byte Java cho CPU. Vì vậy, đối số kích thước là không hợp lệ.
quant_dev

@quant_dev, tất nhiên - Tôi đã nói rằng trường hợp này hoàn toàn không liên quan đến JVM. Bạn sẽ cần một công cụ mã byte đơn giản hơn nhiều để hiệu ứng đó hoạt động.
SK-logic

-1

JIT, GC và v.v., C ++ có thể rất, rất dễ tạo ra chậm chạp hơn nhiều so với Java. Điều này sẽ không hiển thị trong các điểm chuẩn, nhưng cùng một ứng dụng được viết bởi nhà phát triển Java và nhà phát triển C ++ có thể nhanh hơn nhiều trong Java.

  • Vận hành quá tải. Mỗi toán tử đơn giản như "+" hoặc "=" có thể gọi hàng trăm dòng mã thực hiện kiểm tra an toàn, vận hành đĩa, ghi nhật ký, theo dõi và định hình. Và chúng rất dễ sử dụng đến mức một khi bạn làm quá tải các toán tử, bạn sử dụng chúng một cách tự nhiên và đa dạng mà không nhận thấy cách sử dụng sắp xếp.
  • Mẫu. Những điều này không ảnh hưởng đến tốc độ nhiều như bộ nhớ. Việc sử dụng các mẫu không cẩn thận sẽ dẫn đến việc tạo ra hàng triệu dòng mã (các lựa chọn thay thế cho mẫu cơ bản) mà bạn không bao giờ nhận thấy chúng. Nhưng sau đó thời gian tải nhị phân, sử dụng bộ nhớ, sử dụng trao đổi - tất cả những gì cũng chống lại điểm chuẩn. Và việc sử dụng RAM đi qua mái nhà.

Đối với các mẫu thừa kế nâng cao, các mẫu này khá giống nhau - C ++ có một số thứ mà Java không có và ngược lại, nhưng tất cả chúng đều giới thiệu tương tự, chi phí đáng kể cũng vậy. Vì vậy, không có lợi thế đặc biệt về C ++ trong lập trình nặng đối tượng.

Thêm một cảnh báo: GC có thể nhanh hơn hoặc chậm hơn so với việc quản lý phân bổ thủ công. Nếu bạn phân bổ nhiều đối tượng nhỏ, trong môi trường GC thường sẽ phân bổ một phần bộ nhớ và các phần của nó được gửi đi khi cần thiết cho các đối tượng mới. Trong quản lý - mỗi đối tượng = phân bổ riêng biệt mất thời gian đáng kể. OTOH, nếu bạn malloc () nhiều bộ nhớ cùng một lúc và sau đó chỉ cần gán các phần của nó cho các đối tượng của bạn theo cách thủ công hoặc sử dụng một vài trường hợp lớn hơn của các đối tượng, bạn có thể xuất hiện nhanh hơn nhiều.


4
Tôi không đồng ý với cả hai điểm. Cho dù bạn sử dụng toán tử hay phương thức đều không liên quan. Bạn nói rằng họ sẽ sinh sôi nảy nở. Vô nghĩa - không nhiều hơn các phương pháp sẽ; bạn có thể cần gọi cho họ, hoặc không. Và các mẫu dẫn đến không có nhiều mã hơn viết tay mã cụ thể đó một lần nữa để sử dụng nhiều lần. Có thể có nhiều mã hơn so với việc gửi thời gian chạy (các hàm ảo), nhưng điều này cũng sẽ không liên quan: hiệu suất của các dòng bộ đệm hướng dẫn quan trọng nhất trong các vòng lặp chặt chẽ và ở đây sẽ chỉ sử dụng một khởi tạo mẫu, do đó không có áp lực bộ nhớ liên quan do mẫu.
Konrad Rudolph

Suy nghĩ thông thường là phương pháp đắt tiền, người vận hành rẻ. Bạn sử dụng các phương thức khi bạn phải, các nhà khai thác bất cứ khi nào bạn muốn tiết kiệm thời gian và tối ưu hóa. Đây không phải là vấn đề kỹ thuật, nhưng tâm lý - không phải là các nhà khai thác "nặng hơn", chúng chỉ dễ sử dụng hơn và được sử dụng thường xuyên hơn nhiều. (cộng với bạn có thể quá tải một toán tử thường được sử dụng trong một mã có sẵn, làm cho nó hoạt động giống như bản gốc, cộng với một phần bổ sung - và đột nhiên toàn bộ mã sẽ chậm lại đáng kể.
SF.

Tôi tranh luận rằng thực tế tâm lý này là có thật, và ngay cả khi nó là, bạn không có lựa chọn : nếu bạn cần một chức năng, bạn sử dụng nó, cho dù nó được gói gọn trong một toán tử hay một phương thức. Tâm lý học là không liên quan cho sự lựa chọn của bạn về ngữ nghĩa.
Konrad Rudolph

1
Câu hỏi mẹo. Tôi sẽ không đoán thứ hai này, tôi sẽ đo, hành động sau đó . Tôi chưa bao giờ có vấn đề với chiến thuật đó.
Konrad Rudolph

1
@KonradRudolph: Điều này hoàn toàn đúng khi nói về sự rõ ràng và dễ viết mã, làm cho nó không có lỗi và có thể bảo trì. Điểm quan trọng về hiệu quả của việc triển khai thuật toán vẫn còn: nếu bạn sắp viết obj.fetchFromDatabase("key")ba lần trong năm dòng mã cho cùng một khóa, bạn sẽ suy nghĩ kỹ xem có nên lấy giá trị đó một lần và lưu vào biến cục bộ không. Nếu bạn viết obj->"key"với ->bị quá tải để đóng vai trò như cơ sở dữ liệu lấy, bạn đang xa dễ hơn để chỉ để cho nó vượt qua vì chi phí của các hoạt động là không rõ rệt.
SF.

-2

Bằng cách nào đó, Stack Exchange không lấy các điểm xếp chồng khác của tôi để ... không trả lời một cách đáng tiếc ...

Tuy nhiên, câu trả lời được bình chọn nhiều thứ hai ở đây chứa đầy thông tin sai lệch trong quan điểm khiêm tốn của tôi.

Một ứng dụng cuộn bằng tay của một chuyên gia về C / C ++ là LUÔN LUÔN sẽ nhanh hơn nhiều so với một ứng dụng Java, theo giai đoạn. Không có "nhanh như Java hay nhanh hơn". nó chỉ nhanh hơn, chính xác là do các mục bạn trích dẫn dưới đây:

Biên dịch JIT : Bạn có thực sự mong đợi một trình tối ưu hóa tự động sẽ có thông minh của một lập trình viên chuyên gia và xem liên kết giữa ý định và mã mà CPU thực sự sẽ chạy ??? Hơn nữa, tất cả các JIT bạn làm là mất thời gian so với một chương trình đã được biên dịch.

Bộ sưu tập rác là một công cụ chỉ đơn giản là phân bổ các tài nguyên mà một lập trình viên đã quên để phân bổ, theo cách ít nhiều hiệu quả.

Rõ ràng điều này chỉ có thể chậm hơn những gì một chuyên gia (bạn đã chọn thuật ngữ) lập trình viên C sẽ làm để xử lý bộ nhớ của mình (và không có rò rỉ nào trong các ứng dụng được viết chính xác).

Một ứng dụng C được tối ưu hóa hiệu suất biết CPU đang chạy, nó được biên dịch trên nó, điều đó có nghĩa là bạn đã không thực hiện tất cả các bước cho hiệu suất phải không?

Thống kê thời gian chạy Điều này vượt quá hiểu biết của tôi, nhưng tôi nghi ngờ rằng một chuyên gia về C có quá nhiều kiến ​​thức dự đoán chi nhánh để một lần nữa tối ưu hóa tự động hóa -

Các thư viện rất tốt Có nhiều hàm không được tối ưu hóa có sẵn thông qua các thư viện trong Java và điều tương tự cũng đúng trong bất kỳ ngôn ngữ nào, tuy nhiên các thư viện được tối ưu hóa nhất được viết bằng C, đặc biệt là để tính toán.

JVM là một lớp trừu tượng, bao hàm cả những điều tốt đẹp mà nhiều trong số đó ở trên và cũng ngụ ý rằng giải pháp tổng thể chậm hơn theo thiết kế.

Tổng thể, nói chung:

Java không bao giờ có thể đạt được tốc độ của C / C ++ do cách nó hoạt động trong một JVM với rất nhiều bảo vệ, tính năng và công cụ.

C ++ có một lợi thế rõ ràng trong phần mềm được tối ưu hóa, có thể là cho máy tính hoặc trò chơi và thường thấy các triển khai C ++ giành chiến thắng trong các cuộc thi mã hóa đến mức chỉ có thể nhìn thấy các triển khai Java tốt nhất trên trang thứ hai.

Trong thực tế, C ++ không phải là một món đồ chơi và sẽ không cho phép bạn tránh khỏi nhiều lỗi mà hầu hết các ngôn ngữ hiện đại có thể xử lý, tuy nhiên bằng cách đơn giản và kém an toàn hơn, nó vốn đã nhanh hơn.

Và như một kết luận, tôi muốn nói rằng hầu hết mọi người không đưa ra hai xu về điều này, rằng cuối cùng tối ưu hóa là một môn thể thao chỉ dành cho một số ít nhà phát triển may mắn và ngoại trừ trong trường hợp hiệu suất thực sự là mối quan tâm (iE khi nhân phần cứng với 10 sẽ không giúp bạn - hoặc ít nhất là vài triệu), hầu hết các nhà quản lý sẽ thích một ứng dụng không được tối ưu hóa và một tấn phần cứng.


Lần nữa. Thu gom rác không chỉ là một "công cụ xử lý". GC có thể thu gọn cấu trúc của bạn. GC có thể xử lý các tài liệu tham khảo yếu của bạn và giúp bạn cân bằng bộ nhớ đệm theo cách này. Multistage GC làm cho một đống phân bổ nhiều rẻ hơn so với cồng kềnh của bạn, chậm newhoặc malloc(). Nó có thể nói chung nhanh hơn nhiều so với bất kỳ quản lý bộ nhớ thủ công nào - vì bạn sẽ không thể di chuyển các đối tượng theo cách thủ công. Vì vậy, tất cả lý luận của bạn hoàn toàn sai và sai lệch. Kiến thức của bạn về các thuật toán GC và phương pháp tối ưu hóa JIT quá hạn chế.
SK-logic

4
Câu trả lời này chứa đầy những quan niệm sai lầm về những gì người tối ưu hiện đại có thể làm. Mã được tối ưu hóa bằng tay không có cơ hội chống lại điều đó. Nhưng sau đó, C ++ cũng có một trình biên dịch tối ưu hóa.
Konrad Rudolph

Cảm ơn nhận xét SK-logic của bạn, nhưng như bạn nói, GC nói chung thể nhanh hơn rất nhiều, chúng tôi đang nói về những gì sẽ nhanh nhất trong một trường hợp cụ thể, và dường như hầu hết mọi người đều đồng ý rằng mọi thứ mà GC có thể làm một lập trình viên có thể làm, và thậm chí tốt hơn. Tất nhiên bạn có thể định vị lại các đối tượng bằng tay khi bạn có quyền truy cập bộ nhớ trực tiếp .. lol. Kiến thức của tôi về các phần tử JVM chắc chắn còn hạn chế và tôi hy vọng những người đứng đầu Java sẽ cho tôi thấy ánh sáng, không chỉ cho tôi biết những điều tào lao ngẫu nhiên về việc GC có thể làm những thứ mà người ta không thể làm bằng tay (lol ... ngay cả GC cũng phải sử dụng các hướng dẫn CPU;)).
Mẹ ơi.

Konrad, tôi đồng ý rằng tôi phần lớn đánh giá thấp các trình tối ưu hóa hiện đại ... tuy nhiên tôi thấy thú vị khi bạn coi mã được tối ưu hóa bằng tay là kém hơn so với mã được tối ưu hóa tự động. Chính xác thì bạn mong đợi trình biên dịch sẽ thấy rằng một con người không thể?
Mẹ ơi.

1
Đúng . tiếp tục đẩy -1, điều đó sẽ không thay đổi thực tế là C ++ nhanh hơn Java. Tôi có thể không biết nhiều về trình biên dịch hiện đại, nhưng điều đó không tạo ra bất kỳ sự khác biệt nào với điểm chính, điều này đúng và mâu thuẫn với câu trả lời được bình chọn nhiều nhất ở đây. Tại sao C ++ lại là ưu tiên hàng đầu của nVidia trên GPU của họ cho HPC. Tại sao tất cả các trò chơi khác sẽ được viết bằng C ++, tại sao mọi công cụ DB khác sẽ được viết bằng C?
Mẹ ơi.

-4

Tôi đã thấy ít nhất hai mm mm ấn tượng được thực hiện trong Java, để nói rằng nó không đủ nhanh cho các trò chơi là một cách gọi sai. Chỉ vì các nhà thiết kế trò chơi ưa thích C ++ hơn các ngôn ngữ khác nói rằng nó đơn giản không chỉ liên quan đến Java, nó chỉ có nghĩa là các lập trình viên chưa bao giờ thực sự say mê với bất kỳ ngôn ngữ / mô hình lập trình nào khác. Bất cứ điều gì trong bất kỳ ngôn ngữ nào tiên tiến như C / C ++ hoặc thậm chí Java đều có thể tạo ra mã có thể đáp ứng về mặt kỹ thuật hoặc đánh bại đối số tốc độ. Tất cả điều đó tốt và nói đến những gì lập trình viên biết, những gì nhóm làm việc với hầu hết và quan trọng nhất là tại sao họ sử dụng các công cụ nói. Vì chúng ta đang giải quyết khía cạnh phát triển trò chơi của lập trình, nên phải tranh luận nhiều hơn. Đơn giản chỉ cần đặt nó ' Tất cả là về tiền bạc và thời gian cho một doanh nghiệp đã chết khi sử dụng các công cụ đáp ứng QA và trong thế giới thực không ảnh hưởng gì đến lý do xx khi chọn C ++ thay vì Java hoặc bất kỳ ngôn ngữ nào khác. Nó chỉ là một quyết định sản xuất hàng loạt. Ở cấp độ cơ bản nhất của thuật toán điện toán, tất cả những gì chúng ta đang chơi là số không và số không, đối số tốc độ là một trong những đối số ngu ngốc nhất từng được áp dụng cho chơi game. Nếu bạn muốn tốc độ tăng nhanh đến mức đó thì hãy bỏ hoàn toàn ngôn ngữ lập trình và làm việc với lắp ráp có thể là lợi thế tốt nhất cho đến nay.


2
Bức tường văn bản này dường như không thêm bất cứ điều gì chưa được nêu trong các câu trả lời khác. Vui lòng chỉnh sửa câu trả lời của bạn để dễ đọc hơn và vui lòng đảm bảo rằng câu trả lời của bạn giải quyết các điểm không được nêu ra bởi câu trả lời khác. Nếu không, vui lòng xem xét xóa câu trả lời của bạn vì nó chỉ thêm tiếng ồn vào thời điểm này.
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.