2012-09-06 39 views
9

Tôi gặp sự cố này. Tôi có một cơ sở dữ liệu hình ảnh trong Dữ liệu chính. Tôi lấy tất cả hình ảnh (khoảng 80MB) và đặt vào NSMutableArray. Các đối tượng đang bị sự cố một cách chính xác:Sử dụng bộ nhớ dữ liệu chính và cảnh báo bộ nhớ

NSArray *fetchResults = [self.managedObjectContext executeFetchRequest:request error:&error]; 
self.cache = [NSMutableArray arrayWithArray:fetchResults]; 
for (ImageCache *imageObject in self.cache) { 
    NSLog(@"Is fault? %i", [imageObject isFault]); 
} 

Đọc nhật ký, tôi thấy rằng các đối tượng đều đổ lỗi một cách chính xác Tuy nhiên, sử dụng dụng cụ, tôi thấy rằng 80MB bộ nhớ được sử dụng. Tôi nghĩ rằng đây là lý do tại sao Core Data lưu trữ kết quả của nó, và nên giải phóng bộ nhớ khi cần thiết. Nhưng (và đây là "vấn đề" của tôi), nếu tôi mô phỏng một cảnh báo bộ nhớ, không có gì xảy ra! 80MB vẫn còn đó.

Nhìn vào công cụ - phân bổ, các 80MB được sử dụng bởi nhiều Malloc: (ví dụ)

Graph Thể loại trực Bytes # Sống # tạm Nhìn chung Bytes # Nhìn chung # Phân bổ (Net/Nhìn chung) 0 Malloc 176,00 KB 8,59 MB 50 57 18,39 MB 107% 0,00,% 0,00 0 Malloc 200,00 KB 8,20 MB 42 460 98,05 MB 502% 0,00,% 0,04 0 Malloc 168,00 KB 7,05 MB 43 19 10,17 MB 62% 0.00, 0.00%

Đây là một liên kết đến một hình ảnh của toàn bộ cuộc gọi Tree: https://www.dropbox.com/s/du1b5a5wooif4w7/Call%20Tree.png

Bất kỳ ý tưởng nào? Cảm ơn

+0

Có thể dữ liệu lõi giải phóng bộ nhớ trên 'Memory Warning Level 2'? Có thể tạo ra sự cố bộ nhớ thấp với kịch bản của bạn không? – brigadir

+0

Có bất kỳ "phương pháp ma thuật" nào để mô phỏng Cảnh báo bộ nhớ cấp 2 không? Hay "đơn giản" tôi phải tiêu thụ trí nhớ? – LombaX

+0

Tôi không biết bất kỳ phương pháp mô phỏng nào. Bạn nên chạy một ứng dụng "nặng" khác (Appstore chẳng hạn), giữ ứng dụng của bạn ở chế độ nền và theo dõi nhật ký bảng điều khiển và biểu đồ bộ nhớ Công cụ. Cảnh báo 'mức 2' sẽ được đề cập trong bảng điều khiển - vì vậy bạn nên xem biểu đồ bộ nhớ tại thời điểm đó. – brigadir

Trả lời

9

Ok, tôi đã hiểu tại sao điều đó xảy ra. Khi bạn thực hiện một yêu cầu tìm nạp cho một thực thể, ngay cả khi lỗi được kích hoạt, TẤT CẢ DỮ LIỆU của thực thể đó được nạp vào bộ nhớ. Bao gồm dữ liệu nhị phân lớn. Bạn có thể giải quyết việc này bằng nhiều phương pháp:

1- thiết lập này trên NSFetchRequest của bạn: [request setIncludesPropertyValues:NO]; thiết NO, dữ liệu không được nạp vào bộ nhớ cache ngay lập tức, nhưng chỉ theo yêu cầu (khi bạn truy cập vào bất động sản và các lỗi là bị sa thải) Nhưng điều này có một "vấn đề". Ngay cả khi bạn cố gắng để lỗi một lần nữa propery (bởi vì bạn không cần nó ngay lập tức và muốn giải phóng bộ nhớ, sử dụng [self.managedObjectContext refreshObject:object mergeChanges:NO];), bộ nhớ không được giải phóng. Bộ nhớ cache vẫn hoạt động cho đến khi managedObjectContext được đặt lại.

Điều này tốt hơn:

2- bạn có thể chia dữ liệu thành các thực thể riêng biệt. Trong trường hợp của tôi, tôi chỉ có 2 thuộc tính: một url và dữ liệu hình ảnh. Tôi chia dữ liệu thành 2 thực thể với mối quan hệ 1: 1: imagecache và imagedata. Tạo một fetchRequest cho tất cả các hàng của thực thể "imagecache" (với thuộc tính url), và giống như giải pháp trước đó không có bộ nhớ được lưu trữ. Imagic imagecache.relationship.image bị lỗi một cách chính xác. Việc truy cập thuộc tính này đã gây ra lỗi khi kích hoạt và bộ nhớ cache sẽ được lấp đầy. Nhưng trong trường hợp này, làm [self.managedObjectContext refreshObject:object mergeChanges:NO]; trên đối tượng "imagecache" (đối tượng "cha"), dẫn đến giải phóng bộ nhớ cache ngay lập tức và bộ nhớ, làm hỏng thuộc tính imagecache.relationship.image một lần nữa. Chú ý: Không làm trên đối tượng "con", nếu bạn làm [self.managedObjectContext refreshObject:object.relationship mergeChanges:NO], vì lý do nào đó bộ nhớ cache không được giải phóng. Tôi nghĩ rằng đây là lý do tại sao bạn đi qua các mối quan hệ. 3- Tôi đã nói đây chủ yếu là một câu hỏi học thuật, giải pháp "cả ngày" thực sự (hiệu năng tốt hơn và ít đau đầu) cho vấn đề này là tránh lưu dữ liệu lớn bên trong cơ sở dữ liệu lõi. Bạn có thể lưu dữ liệu dưới dạng tệp và chỉ lưu trữ tham chiếu (filepath) hoặc với iOS 5, bạn có khả năng đặt "sử dụng bộ nhớ ngoài" trên bất kỳ thuộc tính "Dữ liệu" nào bên trong mô hình dữ liệu cốt lõi của mình. Điều này sẽ làm tất cả công việc cho bạn.

+1

Hey, tôi chỉ tự hỏi nếu bạn đã từng tìm thấy bất kỳ giải pháp nào khác cho vấn đề này. Thật không may, tôi không có bất kỳ đối tượng bộ nhớ NSData lớn nào mà tôi có thể sử dụng giải pháp 3 cho. Thay vào đó, tôi có hàng trăm nghìn đối tượng được hiển thị dưới dạng chú thích trên bản đồ. Tôi lấy theo lô vì vậy tôi đảm bảo rằng nếu thiết bị không có đủ bộ nhớ, tôi có thể giới hạn số lượng dữ liệu được hiển thị. Nhưng khi tôi nhận được một cảnh báo bộ nhớ và gọi refreshObject: mergeChanges: bộ nhớ không bị ảnh hưởng như bạn đã đề cập, và cuối cùng tôi nhận được một vụ tai nạn bộ nhớ. Có suy nghĩ gì không? – horsejockey

0

Tôi nghĩ bạn nên tải ít đối tượng hơn vào bộ nhớ theo lô.

bộ nhớ do coredata phát hành xảy ra sau hậu trường và bạn không phải lập trình cho nó; tin xấu là nó xảy ra đằng sau hậu trường và do đó có thể 'kỳ diệu' nhai ký ức.

Các cách xung quanh rất nhiều; ví dụ: sử dụng biến vị ngữ để chỉ chọn các hàng bạn hoàn toàn cần; không thực hiện cuộc gọi chung để tìm nạp mọi thứ và sau đó đi qua từng danh sách. Nhiều khả năng bạn sẽ sụp đổ khi bạn thực hiện cuộc gọi chung và CoreData cố gắng tải tất cả các đối tượng.

+0

Có, giải pháp đầu tiên tôi áp dụng là chỉ tìm nạp dữ liệu tôi cần. Đây chủ yếu là câu hỏi "học thuật". Tài liệu hướng dẫn rõ ràng về điều này, việc quản lý bộ nhớ đệm được thực hiện bởi Core Data và tất cả xảy ra sau cảnh, nhưng nó thậm chí còn nói rằng trong trường hợp bộ nhớ thấp, bộ nhớ là miễn phí. Tôi dự kiến ​​sẽ thấy giảm bộ nhớ được sử dụng bởi dữ liệu lõi sau một cảnh báo bộ nhớ. Không nhìn thấy điều này, tôi đã nghĩ có gì đó sai trong mã của tôi ...! Tôi muốn nhìn thấy "với đôi mắt của tôi" Core dữ liệu giải phóng bộ nhớ trong tình trạng bộ nhớ thấp :-) – LombaX

+0

chỉ là một bản cập nhật: Tôi đã cố gắng chiếm bộ nhớ (một vòng lặp đơn giản phân bổ một số NSData trường hợp), nhưng Core dữ liệu KHÔNG BAO GIỜ giải phóng bộ nhớ (Tôi đã thử rất nhiều lần, phân bổ 100MB NSData, sau đó 200, sau đó 300 ... cho đến khi ứng dụng gặp sự cố). Dường như nó lưu trữ tất cả dữ liệu của fetchrequest mà không giải phóng nó, KHÔNG BAO GIỜ! Tôi biết rằng tôi có thể sử dụng các cách tiếp cận khác để đạt được phạm vi của mình, nhưng có vẻ lạ. Ý nghĩa của các thuộc tính bị lỗi nếu chúng tiếp tục sử dụng ram là gì? – LombaX

Các vấn đề liên quan