Tốc độ Java so với C++

Java là ngôn ngữ lập trình chính thức của Android và nó là cơ sở cho nhiều thành phần của hệ điều hành, cộng với nó được tìm thấy ở lõi SDK của Android. Java có một số thuộc tính thú vị làm cho nó khác với các ngôn ngữ lập trình khác như C

[relative_videos title=”Gary giải thích. ” align=”right” type=”custom” videos=”684167,683935,682738,681421,678862,679133″]Trước hết Java không (nói chung) biên dịch thành mã máy gốc. Thay vào đó, nó biên dịch sang ngôn ngữ trung gian được gọi là mã byte Java, tập lệnh của Máy ảo Java (JVM). Khi ứng dụng chạy trên Android, nó được thực thi thông qua JVM, JVM này sẽ chạy mã trên CPU gốc (ARM, MIPS, Intel)

Thứ hai, Java sử dụng quản lý bộ nhớ tự động và như vậy thực hiện bộ thu gom rác (GC). Ý tưởng là các lập trình viên không cần phải lo lắng về việc bộ nhớ nào cần được giải phóng vì JVM sẽ theo dõi những gì cần thiết và khi một phần bộ nhớ không còn được sử dụng, bộ thu gom rác sẽ giải phóng bộ nhớ đó. Lợi ích chính là giảm rò rỉ bộ nhớ trong thời gian chạy

Ngôn ngữ lập trình C hoàn toàn trái ngược với Java ở hai khía cạnh này. Đầu tiên, mã C được biên dịch thành mã máy gốc và không yêu cầu sử dụng máy ảo để giải thích. Thứ hai, nó sử dụng quản lý bộ nhớ thủ công và không có bộ thu gom rác. Trong C, lập trình viên được yêu cầu theo dõi các đối tượng đã được cấp phát và giải phóng chúng khi cần thiết

Mặc dù có những khác biệt về thiết kế triết học giữa Java và C, nhưng cũng có những khác biệt về hiệu suất

Có những khác biệt khác giữa hai ngôn ngữ, tuy nhiên chúng ít ảnh hưởng đến các mức hiệu suất tương ứng. Ví dụ, Java là ngôn ngữ hướng đối tượng, C thì không. C chủ yếu dựa vào số học con trỏ, Java thì không. Và như thế…

Hiệu suất

Vì vậy, trong khi có sự khác biệt về thiết kế triết học giữa Java và C, thì cũng có sự khác biệt về hiệu suất. Việc sử dụng máy ảo sẽ thêm một lớp bổ sung vào Java không cần thiết cho C. Mặc dù sử dụng máy ảo có những ưu điểm bao gồm tính di động cao (i. e. cùng một ứng dụng Android dựa trên Java có thể chạy trên các thiết bị ARM và Intel mà không cần sửa đổi), mã Java chạy chậm hơn mã C vì nó phải trải qua giai đoạn diễn giải bổ sung. Có những công nghệ đã giảm chi phí hoạt động này xuống mức tối thiểu nhất (và chúng tôi sẽ xem xét những công nghệ đó ngay lập tức), tuy nhiên, vì các ứng dụng Java không được biên dịch thành mã máy gốc của CPU của thiết bị nên chúng sẽ luôn chậm hơn

Yếu tố quan trọng khác là người thu gom rác. Vấn đề là việc thu gom rác cần có thời gian, cộng với việc nó có thể chạy bất cứ lúc nào. Điều này có nghĩa là một chương trình Java tạo nhiều đối tượng tạm thời (lưu ý rằng một số loại thao tác Chuỗi có thể không tốt cho việc này) thường sẽ kích hoạt trình thu gom rác, do đó sẽ làm chậm chương trình (ứng dụng)

Google khuyến nghị sử dụng NDK cho 'các ứng dụng sử dụng nhiều CPU như công cụ trò chơi, xử lý tín hiệu và mô phỏng vật lý. '

Vì vậy, sự kết hợp của việc giải thích thông qua JVM, cộng với tải bổ sung do thu gom rác có nghĩa là các chương trình Java chạy chậm hơn trong các chương trình C. Sau tất cả những điều đó, những chi phí phát sinh này thường được coi là một điều xấu cần thiết, một thực tế cố hữu khi sử dụng Java, nhưng lợi ích của Java so với C về mặt thiết kế "viết một lần, chạy mọi nơi" cộng với tính hướng đối tượng của nó

Điều đó được cho là đúng trên máy tính để bàn và máy chủ, nhưng ở đây chúng tôi đang xử lý thiết bị di động và trên thiết bị di động, mọi xử lý bổ sung đều tiêu tốn thời lượng pin. Vì quyết định sử dụng Java cho Android đã được đưa ra trong một số cuộc họp ở đâu đó tại Palo Alto vào năm 2003 nên không có lý do gì để phàn nàn về quyết định đó

Mặc dù ngôn ngữ chính của Bộ công cụ phát triển phần mềm Android (SDK) là Java, nhưng đó không phải là cách duy nhất để viết ứng dụng cho Android. Bên cạnh SDK, Google còn có Bộ công cụ phát triển gốc (NDK) cho phép các nhà phát triển ứng dụng sử dụng các ngôn ngữ mã gốc như C và C++. Google khuyến nghị sử dụng NDK cho “các ứng dụng sử dụng nhiều CPU như công cụ trò chơi, xử lý tín hiệu và mô phỏng vật lý. ”

SDK so với NDK

Tất cả lý thuyết này rất hay, nhưng một số dữ liệu thực tế, một số con số để phân tích sẽ tốt vào thời điểm này. Sự khác biệt về tốc độ giữa ứng dụng Java được tạo bằng SDK và ứng dụng C được tạo bằng NDK là gì? . Thời gian thực hiện các chức năng trong Java và trong C được tính bằng nano giây và được ứng dụng báo cáo để so sánh

[relative_videos title=”Ứng dụng Android tốt nhất. ” align=”left” type=”custom” videos=”689904,683283,676879,670446″]Tất cả điều này nghe có vẻ tương đối cơ bản, tuy nhiên, có một số vấn đề khiến sự so sánh này kém dễ hiểu hơn tôi mong đợi. Nguyên nhân của tôi ở đây là tối ưu hóa. Khi tôi phát triển các phần khác nhau của ứng dụng, tôi thấy rằng những chỉnh sửa nhỏ trong mã có thể thay đổi đáng kể kết quả hoạt động. Ví dụ: một phần của ứng dụng tính toán hàm băm SHA1 của một đoạn dữ liệu. Sau khi hàm băm được tính toán, giá trị hàm băm được chuyển đổi từ dạng số nguyên nhị phân thành một chuỗi con người có thể đọc được. Thực hiện một phép tính băm đơn lẻ không mất nhiều thời gian, vì vậy, để có điểm chuẩn tốt, hàm băm được gọi là 50.000 lần. Trong khi tối ưu hóa ứng dụng, tôi nhận thấy rằng việc cải thiện tốc độ chuyển đổi từ giá trị băm nhị phân sang giá trị chuỗi đã thay đổi đáng kể thời gian tương đối. Nói cách khác, bất kỳ thay đổi nào, dù chỉ là một phần nhỏ của giây, sẽ được phóng đại 50.000 lần

Bây giờ bất kỳ kỹ sư phần mềm nào cũng biết về điều này và vấn đề này không phải là mới cũng không phải là không thể khắc phục được, tuy nhiên tôi muốn đưa ra hai điểm chính. 1) Tôi đã dành vài giờ để tối ưu hóa mã này, để đạt được kết quả tốt nhất từ ​​cả phần Java và C của ứng dụng, tuy nhiên tôi không phải là không thể sai lầm và có thể có nhiều cách tối ưu hóa hơn nữa. 2) Nếu bạn là nhà phát triển ứng dụng thì tối ưu hóa mã của bạn là một phần thiết yếu của quy trình phát triển ứng dụng, đừng bỏ qua nó

Ứng dụng điểm chuẩn của tôi thực hiện ba việc. Đầu tiên, nó liên tục tính toán SHA1 của một khối dữ liệu, bằng Java và sau đó bằng C. Sau đó, nó tính toán 1 triệu số nguyên tố đầu tiên bằng phép chia thử, một lần nữa cho Java và C. Cuối cùng, nó liên tục chạy một hàm tùy ý thực hiện nhiều hàm toán học khác nhau (nhân, chia, với số nguyên, với số dấu phẩy động, v.v.), cả trong Java và C

Hai bài kiểm tra cuối cùng cho chúng tôi mức độ chắc chắn cao về sự bằng nhau của các hàm Java và C. Java sử dụng rất nhiều kiểu dáng và cú pháp từ C và do đó, đối với các hàm  tầm thường, rất dễ sao chép giữa hai ngôn ngữ. Dưới đây là mã để kiểm tra xem một số có phải là số nguyên tố hay không (sử dụng phép chia thử) cho Java và sau đó cho C, bạn sẽ nhận thấy rằng chúng trông rất giống nhau

Sao chép văn bản

public boolean isprime(long a)
{
        if(a == 2){
                return true;
        }else if(a <= 1 || a % 2 == 0){
                return false;
        }
        long max = (long)Math.sqrt(a);
        for(long n= 3; n <= max; n+= 2){
                if(a % n == 0){ return false; }
        }
        return true;
}

Sao chép văn bản

int my_is_prime(long a)
{
        long n;
        if(a == 2){
                return 1;
        }else if(a <= 1 || a % 2 == 0){
                return 0;
        }
        long max = sqrt(a);
        for( n= 3; n <= max; n+= 2){
                if(a % n == 0){ return 0; }
        }
        return 1;
}

So sánh tốc độ thực thi của code như thế này sẽ cho chúng ta thấy tốc độ “thô” của việc chạy các hàm đơn giản ở cả hai ngôn ngữ. Tuy nhiên, trường hợp thử nghiệm SHA1 khá khác biệt. Có hai bộ hàm khác nhau có thể được sử dụng để tính hàm băm. Một là sử dụng các chức năng tích hợp sẵn của Android và hai là sử dụng các chức năng của riêng bạn. Ưu điểm của cách đầu tiên là các chức năng của Android sẽ được tối ưu hóa cao, tuy nhiên đó cũng là một vấn đề vì có vẻ như nhiều phiên bản Android triển khai các chức năng băm này trong C và ngay cả khi các chức năng API của Android được gọi, ứng dụng vẫn chạy C

Vì vậy, giải pháp duy nhất là cung cấp hàm SHA1 cho Java và hàm SHA1 cho C và chạy các hàm đó. Tuy nhiên, tối ưu hóa lại là một vấn đề. Tính toán hàm băm SHA1 rất phức tạp và các chức năng này có thể được tối ưu hóa. Tuy nhiên, tối ưu hóa một chức năng phức tạp khó hơn tối ưu hóa một chức năng đơn giản. Cuối cùng, tôi đã tìm thấy hai hàm (một bằng Java và một bằng C) dựa trên thuật toán (và mã) được xuất bản trong RFC 3174 –  Thuật toán băm an toàn của Hoa Kỳ 1 (SHA1). Tôi đã chạy chúng “nguyên trạng” mà không cố gắng cải thiện việc triển khai

Các JVM khác nhau và độ dài từ khác nhau

Vì Máy ảo Java là một phần quan trọng trong việc chạy các chương trình Java, điều quan trọng cần lưu ý là các triển khai JVM khác nhau có các đặc điểm hiệu suất khác nhau. Trên máy tính để bàn và máy chủ, JVM là HotSpot, được phát hành bởi Oracle. Tuy nhiên Android có JVM riêng. android4. 4 KitKat và các phiên bản trước của Android đã sử dụng Dalvik, được viết bởi Dan Bornstein, người đã đặt tên cho nó theo tên làng chài Dalvík ở Eyjafjörður, Iceland. Nó đã phục vụ tốt cho Android trong nhiều năm, tuy nhiên từ Android 5. 0 trở đi, JVM mặc định đã trở thành ART (Thời gian chạy Android). Trong khi Davlik được biên dịch động các đoạn mã byte ngắn được thực thi thường xuyên thành mã máy gốc (một quy trình được gọi là biên dịch đúng lúc), ART sử dụng trình biên dịch trước thời hạn (AOT) để biên dịch toàn bộ ứng dụng thành mã máy gốc khi nó được . Việc sử dụng AOT sẽ cải thiện hiệu quả thực thi tổng thể và giảm mức tiêu thụ điện năng

ARM đã đóng góp một lượng lớn mã cho Dự án nguồn mở Android để cải thiện hiệu quả của trình biên dịch bytecode trong ART

Mặc dù Android hiện đã chuyển sang ART, nhưng điều đó không có nghĩa là sự kết thúc của việc phát triển JVM cho Android. Vì ART chuyển đổi mã byte thành mã máy, điều đó có nghĩa là có một trình biên dịch tham gia và trình biên dịch có thể được tối ưu hóa để tạo ra mã hiệu quả hơn

Ví dụ: trong năm 2015, ARM đã đóng góp một lượng lớn mã cho Dự án nguồn mở Android để cải thiện hiệu quả của trình biên dịch bytecode trong ART. Được gọi là trình biên dịch Tối ưu hóa, đây là một bước nhảy vọt đáng kể về mặt công nghệ trình biên dịch, ngoài ra, nó còn đặt nền móng cho những cải tiến hơn nữa trong các bản phát hành Android trong tương lai. ARM đã triển khai chương trình phụ trợ AArch64 với sự hợp tác của Google

Tất cả điều này có nghĩa là hiệu quả của JVM trên Android 4. 4 KitKat sẽ khác với Android 5. 0 Lollipop, khác với Android 6. 0 kẹo dẻo

Bên cạnh các JVM khác nhau, còn có vấn đề về 32-bit so với 64-bit. Nếu xem phép thử theo mã chia ở trên, bạn sẽ thấy rằng mã này sử dụng số nguyên dài. Theo truyền thống, số nguyên là 32 bit trong C và Java, trong khi số nguyên dài là 64 bit. Hệ thống 32 bit sử dụng số nguyên 64 bit cần phải thực hiện nhiều công việc hơn để thực hiện phép tính số học 64 bit khi hệ thống chỉ có 32 bit bên trong. Hóa ra việc thực hiện thao tác mô đun (phần còn lại) trong Java trên các số 64 bit bị chậm trên các thiết bị 32 bit. Tuy nhiên có vẻ như C không bị vấn đề đó

Kết quả

Tôi đã chạy ứng dụng lai Java/C của mình trên 21 thiết bị Android khác nhau, với rất nhiều sự trợ giúp từ các đồng nghiệp của tôi tại Android Authority. Các phiên bản Android bao gồm Android 4. 4 KitKat, Android 5. 0 Lollipop (bao gồm 5. 1), Android6. 0 Marshmallow và Android 7. 0 N. Một số thiết bị là 32-bit ARMv7 và một số là thiết bị 64-bit ARMv8

Ứng dụng không thực hiện bất kỳ đa luồng nào và không cập nhật màn hình trong khi thực hiện kiểm tra. Điều này có nghĩa là số lượng lõi trên thiết bị sẽ không ảnh hưởng đến kết quả. Điều chúng tôi quan tâm là sự khác biệt tương đối giữa việc hình thành một tác vụ trong Java và thực hiện nó trong C. Vì vậy, trong khi các kết quả thử nghiệm cho thấy LG G5 nhanh hơn LG G4 (như bạn mong đợi), thì đó không phải là mục đích của các thử nghiệm này

Nhìn chung, các kết quả thử nghiệm được nhóm lại với nhau theo phiên bản Android và kiến ​​trúc hệ thống (i. e. 32-bit hoặc 64-bit). Mặc dù có một số biến thể, nhưng việc phân nhóm rõ ràng. Để vẽ biểu đồ, tôi đã sử dụng kết quả tốt nhất từ ​​mỗi danh mục

Bài kiểm tra đầu tiên là bài kiểm tra SHA1. Đúng như dự đoán, Java chạy chậm hơn C. Theo phân tích của tôi, trình thu gom rác đóng một vai trò quan trọng trong việc làm chậm các phần Java của ứng dụng. Đây là biểu đồ về sự khác biệt phần trăm giữa việc chạy Java và C

Tốc độ Java so với C++

Bắt đầu với điểm kém nhất, Android 5 32 bit. 0, cho thấy mã Java chạy chậm hơn 296% so với C, hay nói cách khác là chậm hơn 4 lần. Một lần nữa, hãy nhớ rằng tốc độ tuyệt đối không quan trọng ở đây, mà là sự khác biệt về thời gian chạy mã Java so với mã C, trên cùng một thiết bị. Android 4 32-bit. 4 KitKat với Dalvik JVM nhanh hơn một chút với 237%. Sau khi chuyển sang Android 6. 0 Marshmallow mọi thứ bắt đầu cải thiện đáng kể với Android 6 64-bit. 0 mang lại sự khác biệt nhỏ nhất giữa Java và C

Bài kiểm tra thứ hai là bài kiểm tra số nguyên tố, sử dụng thử bằng phép chia. Như đã lưu ý ở trên, mã này sử dụng số nguyên dài 64 bit và do đó sẽ ưu tiên bộ xử lý 64 bit

Tốc độ Java so với C++

Đúng như mong đợi, kết quả tốt nhất đến từ Android chạy trên bộ xử lý 64-bit. Đối với Android 6 64-bit. 0, sự khác biệt về tốc độ rất nhỏ, chỉ 3%. Trong khi đối với Android 5 64-bit. 0 là 38%. Điều này chứng tỏ sự cải tiến giữa ART trên Android 5. 0 và trình biên dịch Tối ưu hóa được ART sử dụng trong Android 6. 0. Kể từ Android 7. 0 N vẫn là bản beta phát triển Tôi chưa hiển thị kết quả, tuy nhiên, nó thường hoạt động tốt như Android 6. 0 M, nếu không muốn nói là tốt hơn. Kết quả tồi tệ hơn là đối với các phiên bản Android 32 bit và Android 6 32 bit kỳ lạ. 0 mang lại kết quả tồi tệ nhất của nhóm

Bài kiểm tra thứ ba và cũng là bài kiểm tra cuối cùng thực hiện một hàm toán học nặng nề trong một triệu lần lặp lại. Hàm này thực hiện số học số nguyên cũng như số học dấu phẩy động

Tốc độ Java so với C++

Và ở đây, lần đầu tiên chúng ta có một kết quả mà Java thực sự chạy nhanh hơn C. Có thể có hai cách giải thích cho vấn đề này và cả hai đều liên quan đến việc tối ưu hóa và trình biên dịch Tối ưu hóa từ ARM. Đầu tiên, trình biên dịch Tối ưu hóa có thể đã tạo mã tối ưu hơn cho AArch64, với phân bổ đăng ký tốt hơn, v.v. , hơn trình biên dịch C trong Android Studio. Trình biên dịch tốt hơn luôn có nghĩa là hiệu suất tốt hơn. Ngoài ra, có thể có một đường dẫn qua mã mà trình biên dịch Tối ưu hóa đã tính toán có thể được tối ưu hóa vì nó không ảnh hưởng đến kết quả cuối cùng, nhưng trình biên dịch C đã không phát hiện ra sự tối ưu hóa này. Tôi biết rằng loại tối ưu hóa này là một trong những trọng tâm lớn của trình biên dịch Tối ưu hóa trong Android 6. 0. Vì chức năng này chỉ là một phát minh thuần túy từ phía tôi, nên có thể có một cách để tối ưu hóa mã mà bỏ qua một số phần, nhưng tôi chưa phát hiện ra nó. Lý do khác là việc gọi hàm này, thậm chí một triệu lần, không khiến trình thu gom rác chạy

Giống như bài kiểm tra số nguyên tố, bài kiểm tra này sử dụng số nguyên dài 64 bit, đó là lý do tại sao điểm số cao nhất tiếp theo đến từ Android 5 64 bit. 0. Sau đó là Android 6 32 bit. 0, tiếp theo là Android 5 32-bit. 0 và cuối cùng là Android 4 32 bit. 4

Gói (lại

Nhìn chung C nhanh hơn Java, tuy nhiên khoảng cách giữa hai loại này đã giảm đáng kể với việc phát hành Android 6 64 bit. 0 kẹo dẻo. Tất nhiên trong thế giới thực, quyết định sử dụng Java hay C không phải là trắng đen. Mặc dù C có một số lợi thế, nhưng tất cả giao diện người dùng Android, tất cả dịch vụ Android và tất cả API Android đều được thiết kế để gọi từ Java. C thực sự chỉ có thể được sử dụng khi bạn muốn một canvas OpenGL trống và bạn muốn vẽ trên canvas đó mà không cần sử dụng bất kỳ API Android nào

Tuy nhiên, nếu ứng dụng của bạn có một số công việc nặng nhọc cần thực hiện, thì những phần đó có thể được chuyển sang C và bạn có thể thấy tốc độ được cải thiện, tuy nhiên không nhiều như bạn từng thấy

Cái nào nhanh hơn C hay Java?

Java sử dụng các đối tượng, trong khi C sử dụng các hàm. Java dễ học và sử dụng hơn vì nó ở cấp độ cao, trong khi C có thể làm được nhiều việc hơn và hoạt động nhanh hơn vì nó gần với mã máy hơn.

Tại sao Java chậm hơn C?

Nó làm cho việc thực thi chương trình chậm hơn so với chương trình C++ vì không có thao tác trung gian nào xảy ra để thực thi và biên dịch như Java trong C++ . Lý do khiến chương trình thực thi chậm, có một chi phí rất lớn để bắt đầu mã Java nếu máy ảo không chạy.

Java hay C++ nhanh hơn là gì?

Tốc độ và hiệu suất . C++ được biên dịch thành nhị phân, vì vậy nó chạy ngay lập tức và do đó nhanh hơn các chương trình Java .

Java hay Python hay C cái nào nhanh hơn?

Về tốc độ, Java nhanh hơn Python vì đây là ngôn ngữ được biên dịch. Mất ít thời gian hơn để thực thi mã. Python là một ngôn ngữ được giải thích và nó xác định loại dữ liệu trong thời gian chạy khiến nó chậm hơn tương đối.