2009-08-20 17 views
10

Tôi tự hỏi liệu điều này có ảnh hưởng đến hiệu suất hoặc mức tiêu thụ bộ nhớ không. Tôi cần một NSMutableArray, và lúc đầu tôi chỉ có thể đoán có bao nhiêu đối tượng sẽ được thêm vào. Khoảng 3 đến 5 có thể. Vì vậy, tôi tạo ra nó như thế này:Có bao nhiêu vấn đề nếu tôi tạo NSMutableArray với dung lượng = 3 thay vì dung lượng = 50?

NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:3]; 

Điều gì xảy ra ở đây chính xác khi tạo dung lượng 3 chứ không phải 50 chẳng hạn? Nó sẽ là một ý tưởng tồi để tạo ra nó với công suất 1, khi biết rằng sẽ có ít nhất 20 yếu tố? Hay điều đó không quan trọng, đủ để có một số cơn đau đầu trên nó? Tôi có 10 trong số các mảng này trong ứng dụng của tôi và tất cả chúng đều phải tải lúc bắt đầu.

Trả lời

6

initWithCapacity sẽ gây ra NSMutableArray để preallocate không gian cho số lượng yếu tố đó.

Đẩy thêm dữ liệu vào NSMutableArray vượt quá khả năng đó sẽ gây ra NSMutableArray để tái phân bổ bộ nhớ cơ bản của nó. Sự tái phân bổ này cũng sẽ đòi hỏi toàn bộ mảng được sao chép từ phân bổ cũ (nhỏ hơn) sang phân bổ mới (lớn hơn). Vì vậy, có một hình phạt hiệu suất để làm cho con số này quá nhỏ, nhưng không nhiều.

Chỉ định dung lượng lớn hơn dung lượng thực tế bạn sẽ sử dụng bộ nhớ, vì sẽ có bộ nhớ được phân bổ cho các mục sẽ không bao giờ được sử dụng.

Đề xuất của tôi sẽ là nếu bạn biết kích thước mảng của bạn thường sẽ không vượt quá N mục, hãy gọi initWithCapacity:N. Các hình phạt hiệu suất của các đôi khi thường xuyên hơn NSMutableArray lớn hơn N là chấp nhận được, và nó là một hình phạt bạn sẽ không phải trả tiền cho những mảng mà không vượt quá giới hạn đó.

+0

chi tiết tuyệt vời! các câu trả lời khác cũng tuyệt vời. tìm thấy nó không bao giờ khó khăn như vậy để chọn một như được chấp nhận. tất cả đã bỏ phiếu. cảm ơn tất cả! –

+2

Với tất cả sự tôn trọng, tôi nghĩ câu trả lời này là không chính xác. Mặc dù dung lượng được sử dụng để gợi ý trong một số trường hợp nhất định, nhưng không phải là trường hợp tạo ra một mảng có thể thay đổi với dung lượng của gigabyte sẽ ngay lập tức phân bổ một gigabyte bộ nhớ. Nếu bạn không tin tôi, hãy tự mình thử. NSMutableArray * bigArray = [[NSMutableArray alloc] initWithCapacity: 1024 * 1024 * 1024]; nếu (! BigArray) { NSLog (@ "Array không được tạo!"); } else { NSLog (@ "Yep, nó đã được tạo."); } Nếu bạn thực sự ĐIỀN mảng này, bạn sẽ thấy mức sử dụng bộ nhớ tăng lên. Không phải trước đây. – peterb

+0

Tài liệu cho initWithCapacity nói rằng nó trả về "một mảng được khởi tạo với đủ bộ nhớ để giữ các đối tượng numItems." Dường như có sự khác biệt giữa những gì peterb đã quan sát và những gì các tài liệu tuyên bố. – fbrereto

6

Nó không phải là một việc lớn trừ khi bạn đang nói về sự lặp lại cực hay mảng lớn. Nó không phải là giá trị cố gắng để tối ưu hóa trừ khi nó trở thành một nút cổ chai thực sự.

EDIT: Tôi muốn thêm một trích dẫn từ Donald Knuth:

sớm tối ưu hóa là gốc rễ của mọi tội lỗi.

+0

điều đó có nghĩa là gì? Tiếng Anh của tôi không phải là tuyệt vời ;-) xin vui lòng giải thích. cảm ơn! –

+2

Điều này có nghĩa là: không tối ưu hóa hiệu suất mã của bạn cho đến khi và trừ khi bạn a) thực sự cần nó để chạy nhanh hơn và b) xác định các phần chậm. Nếu không, bạn chỉ cần làm cho mã của bạn phức tạp hơn, thêm độ phức tạp và thời gian dành cho không có lợi ích. –

+0

có ý nghĩa :-) –

3

Có câu trả lời lý thuyết và câu trả lời thực tế. Về lý thuyết, việc thiết lập dung lượng lớn hơn có thể thay đổi chiến lược phân bổ và lưu trữ cho mảng (mặc dù được gọi là "NSArray" bên trong cấu trúc phức tạp hơn một chút).

Từ quan điểm thực tế, mảng sẽ phân bổ lại khi cần và với số bạn đang nói về tôi nghi ngờ sẽ có bất kỳ sự khác biệt nào. Tôi có thể làm một arrayWithCapacity nếu tôi biết tôi muốn được đặt hàng ngàn khi hàng ngàn mặt hàng in 3 so với 50 về cơ bản là vô nghĩa.

Cách sử dụng tốt nhất cho "withCapacity" từ quan điểm của tôi là cung cấp một móc rõ ràng để treo các giả định của bạn, vì vậy bạn có thể (ví dụ) có tài liệu trong mã về điều gì đó mà sau này bạn có thể muốn khẳng định. nhưng không cần thiết.

Từ góc độ thực tế, việc sử dụng thời gian của bạn tốt nhất là thậm chí không suy nghĩ về vấn đề này.

0

Trong khi nó chắc chắn không làm tổn thương để sử dụng initWithCapacity: như những người khác đề cập ở đây, bạn nên kiểm tra this research về hiệu suất mảng khởi tạo từ Bartosz Ciechanowski:

công suất ban đầu gần như không quan trọng

Hãy phân bổ mảng mới với công suất ban đầu được đặt thành lũy thừa liên tiếp của hai:

for (int i = 0; i < 16; i++) { 
    NSLog(@"%@", [[[NSMutableArray alloc] initWithCapacity:1 << i] explored_description]); 
} 

Bất ngờ ngạc nhiên:

size: 2 // requested capacity: 1 
size: 2 // requested capacity: 2 
size: 4 // requested capacity: 4 
size: 8 // requested capacity: 8 
size: 16 // requested capacity: 16 
size: 16 // requested capacity: 32 
size: 16 // requested capacity: 64 
size: 16 // requested capacity: 128 
... 
// 'size: 16' all the way down 
Các vấn đề liên quan