Tôi đã cố gắng để thấy sự khác biệt hiệu suất giữa trước khi khởi tạo một ArrayList
đến một khả năng nhất định vs đi với khả năng mặc định và mở rộng theo yêu cầu. Chỉ tò mò thôi. Tôi thấy rằng mã mảng dung lượng mặc định là ~ 10% FASTER so với mã khởi tạo mảng với công suất được yêu cầu. Đây là mã tôi đã sử dụng:Hiệu suất của ArrayList
public class Test {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
for(int j=0;j<10;++j) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<1000000;++i) {
list.add(i);
}
}
long t2 = System.currentTimeMillis();
System.out.println("Time taken: " + (t2-t1)/10.0);
}
}
tôi luôn có được ~ 77 ms cho phiên bản này trên hộp của tôi, trong khi tôi nhận được ~ 85 ms nếu tôi thay đổi danh sách khởi tạo để new ArrayList<Integer>(1000000)
. Tại sao nó như vậy? Nó không phải là cách khác vòng? Trong thực tế, Danh sách không có tiền tố init luôn nhỏ hơn một chút (~ 0,5-1 ms) nhanh hơn so với sử dụng đồng bằng Integer[]
. Về cơ bản, những gì nó nói là default capacity arraylist > simple array > pre-capacity-ensured arraylist
trong hiệu suất chèn.
Điều này rất lạ đối với tôi. Đoán ban đầu của tôi là nó có cái gì đó để làm với phân bổ bộ nhớ, một cái gì đó giống như cho 1000000 khối int trong một đi là có thể chậm hơn so với từ từ nhận được nhiều không gian hơn? Điều này thậm chí có thể tái sản xuất trong các máy khác? Tôi đang sử dụng jdk 1.6.0, Mac OS X, chạy qua nhật thực.
Tôi đã thử trong hai môi trường khác: -> Đã thử chạy java + javac từ dòng lệnh thay vì nhật thực - Ở đây tôi nhận được pre-capacity-ensured arraylist > simple array > default capacity arraylist
, nhất quán.
-> Đã thử chạy java + javac trên máy tính để bàn Linux (RHEL) của tôi. Hộp này có RAM 24 GB, trong khi máy tính xách tay của tôi chỉ có 8 GB. Ở đây, tôi nhận được plain array >>> default capacity arraylist > pre-capacity-ensured arraylist
. Mảng đồng bằng là siêu nhanh, nhanh hơn khoảng 2-3 lần trong trường hợp này so với hai loại còn lại.
EDIT: Sau @ đề nghị JonSkeet của trong các ý kiến, tôi đã sử dụng nanoTime()
, và Integer
thay vì int
. Nó vẫn không giải quyết vấn đề mà JIT hâm nóng không được xem xét mặc dù. Sau những thay đổi này, tôi nhất quán thấy rằng mảng đồng bằng là nhanh nhất trong tất cả các thử nghiệm. Nhưng danh sách đảm bảo dung lượng vẫn chậm hơn khoảng 5-10% so với danh sách dung lượng mặc định cho tôi trên tất cả 3 môi trường ở trên. NHƯNG một số người dùng dường như có được hành vi chính xác, vì vậy đây có thể là một trường hợp rất cụ thể.
EDIT2: Nếu tôi sử dụng String thay vì Integer làm phần tử, hành vi là chính xác (plain array > pre-capacity-ensured arraylist > default capacity array
). Vì vậy, tôi nghĩ autoboxing thực sự là thủ phạm.
Để bắt đầu, đây là * không * một cách tốt để điểm chuẩn. Bạn đang bao gồm thời gian khởi động JIT và bạn đang sử dụng 'currentTimeMillis' thay vì' nanoTime'. Hãy thử với https://code.google.com/p/caliper/ - cũng có, tôi nghi ngờ rằng rất nhiều thời gian của bài kiểm tra của bạn được dành đấm bốc một triệu 'int' giá trị. Hãy thử sử dụng một cái gì đó mà bạn * không * cần phải tạo một đối tượng mới trên mỗi lần lặp. –
Chỉ là một mẹo hữu ích: Chạy thử nghiệm của bạn hai lần và xem kết quả của lần chạy thứ hai. Lần chạy đầu tiên thường bị nhiễm độc vì tải VM theo yêu cầu. – Kylar
Tôi đã thay đổi vòng lặp bên ngoài để chạy 100 lần lặp lại và thấy phiên bản preallocating nhanh gấp hai lần. –