2009-12-22 46 views
29

Tôi có một số câu hỏi liên quan đến đối tượng Bitmap và bộ nhớ và phân loại chung của chúng.Ảnh bitmap trong Android

  1. Bitmap trong bộ nhớ hoặc bản địa là gì?
  2. Bộ nhớ bitmap khác với bộ nhớ Heap như thế nào?

Trả lời

33

Bộ nhớ sao lưu đối tượng Bitmap được cấp phát bằng mã gốc (malloc()), thay vì từ khóa Java new. Điều này có nghĩa là bộ nhớ được quản lý trực tiếp bởi hệ điều hành, chứ không phải bởi Dalvik.

Sự khác biệt thực sự duy nhất giữa vùng heap bản địa và vùng heap của Dalvik là đống của Dalvik là rác được thu thập, và vùng gốc không phải là.

Mặc dù vậy, đây không phải là sự khác biệt nhiều. Khi đối tượng Bitmap của bạn bị thu thập rác, đó là destructor sẽ tái chế bộ nhớ liên quan trong heap nguyên gốc.

Nguồn:

+0

Bạn có biết liệu lỗi này đã từng được sửa chưa? Tôi hiện đang chạy vào cùng một vấn đề trên sấm sét. Tôi đang tái chế các bitmap nhưng chúng không bao giờ xóa bất kỳ khoảng trống nào trên vùng heap nguyên gốc gây ra lỗi oom. –

+5

Chỉ để rõ ràng, câu trả lời ở trên là đúng cho phiên bản Android 2.x trở xuống. Bắt đầu với Android 3, các bản sao bitmap được truy cập một lần nữa đống. Điều này có thể dễ dàng được kiểm tra: tạo ra một bitmap trong android 2.x sẽ để lại kích thước heap Java khá nhiều intouched, tạo ra nó trong Adnroid 3.x sẽ thêm rất nhiều byte vào đống Java. –

+0

Ah! vì vậy bạn đang nói việc đếm giờ đây trực quan hơn nhiều? Đó là tuyệt vời - ngoại trừ tất cả chúng ta đã viết mã hacky để tổng hợp heap android với heap bản địa ... –

32

Có một sự tinh tế quan trọng ở đây: mặc dù pixel Bitmap được phân bổ trong đống bản xứ, một số thủ thuật đặc biệt trong Dalvik nguyên nhân nó sẽ được tính vào đống Java. Điều này được thực hiện vì hai lý do:

(1) Để kiểm soát lượng bộ nhớ mà ứng dụng phân bổ. Nếu không có kế toán, một ứng dụng có thể cấp phát một lượng lớn bộ nhớ (vì bản thân đối tượng Bitmap là rất nhỏ nhưng có thể giữ lại một lượng lớn bộ nhớ riêng), mở rộng vượt quá giới hạn 16MB hoặc 24MB.

(2) Để giúp xác định thời điểm đến GC. Nếu không có kế toán, bạn có thể phân bổ và giải phóng các tham chiếu về nói 100 đối tượng Bitmap; GC sẽ không chạy, bởi vì các đối tượng này rất nhỏ, nhưng thực ra chúng có thể đại diện cho một số lượng lớn các phân bổ thực tế hiện không được GCed một cách kịp thời. Bằng cách kế toán các phân bổ này dựa vào vùng heap Java, bộ gom rác sẽ chạy vì nó cho rằng bộ nhớ đang được sử dụng.

Lưu ý rằng bằng nhiều cách, đây là chi tiết triển khai; rất có khả năng nó có thể thay đổi trong tương lai, mặc dù hành vi cơ bản này sẽ vẫn ở dạng nào đó vì đây là cả hai đặc điểm quan trọng để quản lý phân bổ bitmap.

+1

Ngay cả trên điện thoại đếm bitmap chống lại đống java, malloc bản địa có thể phân bổ WAY hơn 16 MiB. –

+10

Nhận xét đầu tiên là sai, tất cả các điện thoại đều tính các phân bổ bitmap dựa vào giới hạn heap Dalvik. Sự thay đổi chính để nhận thức được là khi Android 3.0 phân bổ thực sự được thực hiện trong vùng Dalvik, vì vậy bạn không còn phải đối phó với các tình huống mà GC sẽ không chạy mạnh như nó cần. – hackbod

+2

bạn đã đúng vào thời điểm đó. Tuy nhiên, GC bị chậm khi nói đến việc xử lý các bitmap tái chế. Tôi đã tìm thấy hành vi không thể đoán trước trừ khi tôi chạy GC theo cách thủ công sau khi tái chế một bitmap (bao gồm cả xu hướng cho "tải" tiếp theo để trả về một bản sao của bitmap tái chế thay vì thực sự tải nó từ đĩa) –

12

Từ triển khai trong tự nhiên, tôi đã tìm thấy các thiết bị sau:

  • Thiết bị làm hạn chế đến 16 MiB của đống java (bitmap gần không giới hạn).
  • Thiết bị giới hạn ở 16 MiB (bộ nhớ heap + bitmap gốc)
  • Thiết bị giới hạn ở 24 MiB heap java (bitmap gần như không giới hạn).
  • Thiết bị làm hạn chế đến 24 MiB của (java đống + lưu trữ bitmap mẹ đẻ)

24 MiB có xu hướng được các thiết bị res cao, và có thể được phát hiện với Runtime.getRuntime(). MaxMemory(). Ngoài ra còn có 32MiB thiết bị hiện nay, và một số điện thoại bắt nguồn có 64MiB theo mặc định. Trước đây, tôi lúng túng với bản thân mình nhiều lần cố gắng tìm ra những gì đang xảy ra. Tôi nghĩ rằng tất cả các thiết bị đếm bitmap vào giới hạn đống. Nhưng thật khó để thực hiện bất kỳ khái quát chung nào về hạm đội Android.

Đây là sự cố RẤT khó chịu trên Android và rất khó hiểu. Giới hạn này và hành vi của nó kém tài liệu, phức tạp và cực kỳ không trực quan. Chúng cũng khác nhau giữa các thiết bị và các phiên bản hệ điều hành, và có một số lỗi đã biết. Một phần của vấn đề là các giới hạn không chính xác - do phân mảnh heap, bạn sẽ nhấn OOM tốt trước giới hạn thực tế và phải bảo toàn để lại một meg hoặc hai bộ đệm. Thậm chí tệ hơn, tôi có một số thiết bị có segfault bản địa (100% lỗi trong chính Android) xảy ra trước khi bạn nhận được ngoại lệ OOM java, làm cho nó quan trọng gấp đôi để không bao giờ đạt đến giới hạn vì bạn thậm chí không thể bắt được tai nạn gốc. Để biết thêm chi tiết về các điều tra của tôi, hãy xem this post. Trong cùng một bài đăng, tôi giải thích cách đo lường mức sử dụng so với giới hạn và tránh sự cố.

Kích thước của vùng heap java là Runtime.getRuntime(). TotalMemory().

Không có cách nào dễ dàng để đo kích thước của bộ nhớ bitmap gốc. Heap gốc tổng thể có thể được đo bằng Debug.getNativeHeapAllocatedSize(), nhưng chỉ các bitmap được tính vào giới hạn (tôi nghĩ).

+0

Vì bất kỳ ai cũng có thể phát hành phiên bản Android của riêng mình, có vẻ như rất đáng tin cậy rằng có thể có các phiên bản thực hiện các chính sách khác nhau để hạn chế bộ nhớ heap, bao gồm cả những thứ bạn mô tả ở trên. Ví dụ, CyanogenMod cho phép người dùng tự đặt giới hạn heap, vì vậy tôi không thấy lý do tại sao không thể có bản phát hành hệ điều hành thực hiện các chính sách về giới hạn mà bạn mô tả. Tôi muốn được quan tâm để biết liệu có bất kỳ hướng dẫn chính thức trong vấn đề này. Nếu không, thì chúng ta sẽ phải chịu sự thay đổi của các biến thể OS đó. – Carl

+0

@Carl.Từ những gì tôi có thể nói, đó là sự hỗn loạn thuần khiết. Mặc dù nói chung, các mod và điện thoại bắt nguồn từ có xu hướng tăng giới hạn heap, thường là 64M. Quyết định giới hạn kích cỡ đống Java nghiêm trọng đến mức đã làm chậm trí não và kết quả là trải nghiệm người dùng khủng khiếp. –

+0

Nó buộc chúng tôi là nhà phát triển để có một cái nhìn khó khăn về việc sử dụng bộ nhớ của chúng tôi. Tôi hiện đang phát triển một ứng dụng có một tập dữ liệu rất lớn * phải * cư trú hoàn toàn trên heap (vì quá trình tìm kiếm chuyên sâu) và triển khai dựa trên mảng String ban đầu của tôi chiếm 15 MB đống dữ liệu đó một mình (mỗi chuỗi ref trong mảng mất 32 byte dữ liệu). Sau khi gần đạt đến giới hạn 24 MB mà nhiều thiết bị hiện tại vẫn áp đặt, tôi đã thiết kế cấu trúc dữ liệu tùy chỉnh chỉ mất 3,5MB để giữ chính xác cùng một thông tin. Bây giờ ứng dụng của tôi sẽ chạy ngay cả trên thiết bị có giới hạn 16MB. – Carl

-1

Chúng tôi có thể tăng kích thước heap bằng cách sử dụng android:largeheap="true" trong tệp kê khai của bạn. Điều này sẽ giải quyết một số vấn đề của bạn.

+0

Hãy suy nghĩ về pin của người dùng của bạn ... Yêu cầu một phần lớn để bù đắp một số sai lầm về phân bổ bộ nhớ, rõ ràng không thể là một giải pháp. – JuSchz

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