5

Tôi đã làm một số thử nghiệm hiệu suất liên quan đến phân bổ đối tượng, khi tôi đi qua một kết quả lạ. Tôi có đoạn code java sau:Java: Điều gì làm tăng hiệu suất khi liên tục gọi một hàm?

public static long TestMethod(){ 
    int len = 10000000; 
    Object[] obs = new Object[len]; 
    long t = System.nanoTime(); 
    for (int i = 0; i < len; i++) { 
     obs[i] = new Object(); 
    } 
    return System.nanoTime() - t; 
} 

public static void main(String... args) throws InterruptedException { 
    for(int i = 0; i < 10; i++){ 
     System.gc(); 
     System.gc();//Wait for the gc to be finished 
     Thread.sleep(1000); 
     System.out.println(TestMethod()); 
    } 
} 

vọng: cuộc gọi đầu tiên sẽ chậm hơn sau đó cuộc gọi thứ hai, do yêu cầu một không gian bộ nhớ lớn hơn từ hệ điều hành và cải tiến hotspot. Nhưng thứ hai và thứ ba sẽ gần như giống nhau.

kết quả quan sát được:

11284734000 
799837000 
682304000 
304736000 
380770000 
392786000 
374279000 
381611000 
379174000 
407256000 

Vẫn là một tốc độ đáng kể lên giữa phiên thứ ba và thứ tư. Điều gì gây ra sự tăng tốc này? Làm thế nào tôi có thể chắc chắn các phép đo của tôi là chính xác khi kiểm tra các chức năng khác, tôi có phải gọi hàm này nhiều hơn bốn lần trước khi đo không?

+0

[Just-in-time delay biên dịch khởi động] (http://en.wikipedia.org/wiki/Just-in-time_compilation#Startup_delay_and_optimizations) –

+1

Thú đọc: http://stackoverflow.com/questions/504103/how-do-i-write-a-chính xác-vi-điểm chuẩn-in-java - Đặc biệt, chạy với '-XX: + PrintCompilation -verbose: gc' VM tham số sẽ giúp bạn hiểu những gì đang xảy ra. – assylias

+0

@assylias: Thú vị. Không biết những thông số đó. Nó có vẻ là biên dịch lại chức năng trong cuộc gọi thứ hai, và thực hiện 2 bộ sưu tập rác trong ba cuộc gọi đầu tiên, và các cuộc gọi cuối cùng không thực hiện thu gom rác trong các cuộc gọi hàm. – user23127

Trả lời

4

Điều gì gây ra sự tăng tốc này?

Nó rất có khả năng biên dịch JIT, nhưng nó cũng có thể là đóng góp từ tải mã và/hoặc hiệu ứng heap ấm lên.

Làm cách nào để đảm bảo số đo của tôi là chính xác khi kiểm tra các chức năng khác, tôi có phải gọi chức năng hơn bốn lần trước khi đo không?

Bạn cần làm điều gì đó tương tự. Không có cách nào khác để loại bỏ các hiệu ứng khởi động JVM khỏi các phép đo của bạn và vẫn nhận được các kết quả đại diện. Việc viết "điểm chuẩn vi mô" hợp lệ cho Java là khó khăn và bạn cần đọc tất cả các vấn đề trước khi thử. Bắt đầu với điều này: How do I write a correct micro-benchmark in Java?


Tôi cũng xin lưu ý một vài điều khác:

  1. nỗ lực của bạn để loại bỏ các chi phí thu gom rác thải từ các phép đo của bạn (tôi giả sử đó là những gì bạn dường như là đi) xuất hiện để không thành công. Có vẻ như bạn đang nhận được các bộ sưu tập nhỏ trong khi thực hiện testMethod.Điều đó sẽ giải thích sự thay đổi ~ 7% trong kết quả "trạng thái ổn định" của bạn.

  2. Tách chi phí phân bổ một đối tượng khỏi chi phí giải phóng nó có thể mang lại cho bạn kết quả gây hiểu lầm. Chi phí "tổng" phân bổ một đối tượng bao gồm chi phí của zeroing bộ nhớ khi nó được tái chế ... và được thực hiện bởi bộ thu gom rác.

  3. Thực tế, biện pháp hữu ích nhất là chi phí phân bổ cho mỗi đối tượng của chu kỳ phân bổ/thu thập. Và điều đó (đáng ngạc nhiên) phụ thuộc vào số lượng không rác khi GC chạy ... đó là điều mà điểm chuẩn của bạn không tính đến.

2

Có nhiều yếu tố có thể đẩy nhanh tiến độ thực hiện các chức năng, như bạn đã nêu:

  • nhất của tất cả các JIT có thể xảy ra tại deegrees khác nhau hoặc thời điểm trong ứng dụng của bạn (đây là lý do tại sao hồ sơ mà không cần đưa ra JVM đủ thời gian cho ấm lên có thể dẫn đến kết quả sai lệch)
  • theo yêu cầu của bộ nhớ cho hệ điều hành
  • việc tái sử dụng bộ nhớ trên heap cho các đối tượng mà bạn đang phân bổ

Bạn không thể chắc chắn khi nào mỗi bước xảy ra và bạn không thể biết khi nào các đoạn mã được biên dịch thành mã gốc, nhưng giả định rằng điều này xảy ra ngay trước khi cuộc gọi đầu tiên không chính xác, nó có thể xảy ra chính xác lặp thứ ba và thứ tư hoặc bất cứ thứ gì. Rất tiếc, các chi tiết này được ẩn bên trong triển khai JVM.