Dung lượng RAM tối đa mà một ứng dụng có thể sử dụng là bao nhiêu?


145

Tôi khá tò mò về câu hỏi này liên quan đến việc quản lý bộ nhớ của hệ điều hành Android vì vậy tôi hy vọng câu trả lời khá chi tiết về chủ đề đó.

Những gì tôi muốn biết:

  • Là gì số tiền tối đa bộ nhớ (trong MB / như tỷ lệ phần trăm của tổng số RAM) mà một ứng dụng Android (mà không phải là một ứng dụng hệ thống) có thể sử dụng không?
  • Có sự khác biệt nào giữa các phiên bản Android không?
  • Có sự khác biệt nào liên quan đến nhà sản xuất thiết bị không?

Và quan trọng nhất:

  • Điều gì được xem xét / nó phụ thuộc vào điều gì khi nói đến hệ thống xác định mức độ RAM mà ứng dụng có thể sử dụng trong thời gian chạy (giả sử rằng tối đa bộ nhớ cho mỗi ứng dụng không phải là số tĩnh)?

Những gì tôi đã nghe cho đến nay (cho đến năm 2013):

  • Các thiết bị Android đời đầu có giới hạn cho mỗi ứng dụng là 16MB
  • Sau đó, giới hạn này tăng lên 24MB hoặc 32MB

Điều khiến tôi rất tò mò:

Cả hai giới hạn này đều rất thấp.

Tôi vừa mới tải xuống Trình quản lý tác vụ Android để kiểm tra RAM thiết bị của mình. Những gì tôi đã nhận thấy là có những ứng dụng sử dụng khoảng 40-50 megabyte RAM, điều này gây khó chịu hơn so với mức sử dụng RAM tối đa được đề cập của giả sử là 32 MB. Vậy làm thế nào để Android xác định ứng dụng có thể sử dụng bao nhiêu RAM? Làm thế nào có thể các ứng dụng vượt quá giới hạn đó?

Hơn nữa, tôi nhận thấy rằng một số ứng dụng của sự cố của tôi (bị hệ thống tiêu diệt?) Với OutOfMemoryException khi sử dụng khoảng 30-40 Megabyte. Mặt khác, tôi có các ứng dụng chạy trên điện thoại của mình sử dụng 100 MB và hơn thế nữa sau một thời gian (có thể do rò rỉ bộ nhớ) mà không bị sập hoặc bị tắt. Vì vậy, rõ ràng nó cũng phụ thuộc vào chính ứng dụng khi xác định dung lượng RAM có thể được tiết kiệm. Sao có thể như thế được? (Tôi đã tiến hành thử nghiệm với HTC One S với RAM 768 MB)

Tuyên bố miễn trừ trách nhiệm: Tôi KHÔNG liên kết với ứng dụng Trình quản lý tác vụ Android dưới bất kỳ hình thức nào.

Câu trả lời:


119

Dung lượng bộ nhớ tối đa (tính bằng Megabyte / phần trăm của tổng RAM) mà một ứng dụng Android (không phải là ứng dụng hệ thống) có thể sử dụng là bao nhiêu?

Điều đó thay đổi tùy theo thiết bị. getMemoryClass()bậtActivityManager sẽ cung cấp cho bạn giá trị cho thiết bị mà mã của bạn đang chạy.

Có sự khác biệt nào giữa các phiên bản Android không?

Có, trong chừng mực mà các yêu cầu hệ điều hành đã tăng lên trong những năm qua và các thiết bị phải điều chỉnh để phù hợp.

Có sự khác biệt liên quan đến nhà sản xuất thiết bị?

Có, trong chừng mực khi các nhà sản xuất sản xuất thiết bị và kích thước thay đổi tùy theo thiết bị.

Những "yếu tố phụ" nào được xem xét khi xác định ứng dụng có thể sử dụng bao nhiêu RAM?

Tôi không biết "yếu tố phụ" nghĩa là gì.

Các thiết bị ban đầu có giới hạn cho mỗi ứng dụng là 16MB; Các thiết bị sau này tăng lên 24MB hoặc 32MB

Điều đó đúng. Độ phân giải màn hình là một yếu tố quyết định quan trọng, vì độ phân giải lớn hơn có nghĩa là bitmap lớn hơn và do đó, máy tính bảng và điện thoại có độ phân giải cao sẽ có xu hướng có giá trị cao hơn. Ví dụ: bạn sẽ thấy các thiết bị có đống 48 MB và tôi sẽ không ngạc nhiên nếu có giá trị cao hơn thế.

Làm thế nào có thể các ứng dụng vượt quá giới hạn đó?

Bạn cho rằng tác giả của ứng dụng đó biết anh ấy đang làm gì. Xem xét rằng việc sử dụng bộ nhớ của một ứng dụng là khó khăn đối với một kỹ sư Android cốt lõi để xác định , tôi sẽ không cho rằng ứng dụng đang được đề cập là nhất thiết phải cung cấp kết quả đặc biệt chính xác.

Điều đó đang được nói, mã gốc (NDK) không phải chịu giới hạn heap. Và, kể từ Android 3.0, các ứng dụng có thể yêu cầu một "đống lớn", thường là trong phạm vi hàng trăm MB, nhưng đó được coi là hình thức kém cho hầu hết các ứng dụng.

Hơn nữa, tôi nhận thấy rằng một số ứng dụng của tôi gặp sự cố với OutOfMemoryException khi sử dụng khoảng 30-40 Megabyte.

Hãy nhớ rằng trình thu gom rác Android không phải là trình thu gom rác. Ngoại lệ thực sự nên có CouldNotFindSufficientlyLargeBlockOfMemoryException, nhưng điều đó có thể được coi là quá dài dòng. OutOfMemoryExceptioncó nghĩa là bạn không thể phân bổ khối yêu cầu của bạn , không phải là bạn đã sử dụng hết đống của mình.


Tôi không thể hiểu về bảng, tôi có điện thoại di động Xperia X có độ phân giải khoảng 1080 x 1920, độ phân giải lớn và một thiết bị khác Samsung Tab 4 có độ phân giải là 800 x 1280, vì vậy hãy sử dụng ram tương tự, vui lòng hướng dẫn cho tôi vì di động đi kèm RAM 3 GB và tab đi kèm với 1,5 GB RAM, vậy máy tính bảng chiếm ram lớn vì màn hình lớn?
Rahul Mandaliya

@RahulMandaliya: Tôi xin lỗi, nhưng tôi không hiểu mối quan tâm của bạn hoặc những gì nó phải làm với câu hỏi này. Bạn có thể muốn mở một câu hỏi Stack Overflow riêng biệt nơi bạn giải thích chi tiết mối quan tâm của bạn là gì.
CommonsWare

15

Đã cuối năm 2018 nên mọi thứ đã thay đổi.

Trước hết: chạy ứng dụng của bạn và mở tab Android Profiler trong Android Studio. Bạn sẽ thấy nó tiêu thụ bao nhiêu bộ nhớ, bạn sẽ ngạc nhiên nhưng nó có thể phân bổ rất nhiều RAM.

Ngoài ra đây là một bài viết tuyệt vời trong các tài liệu chính thức với các hướng dẫn chi tiết về cách sử dụng Memory Profiler có thể cung cấp cho bạn cái nhìn sâu sắc về quản lý bộ nhớ của bạn.

Nhưng trong hầu hết các trường hợp, Android Profiler thông thường của bạn sẽ đủ cho bạn.

nhập mô tả hình ảnh ở đây

Thông thường, một ứng dụng bắt đầu với phân bổ RAM 50Mb nhưng ngay lập tức nhảy lên tới 90Mb khi bạn bắt đầu tải một số ảnh trong bộ nhớ. Khi bạn mở Activity bằng ViewPager với các ảnh được tải sẵn (mỗi ảnh 3,5Mb), bạn có thể nhận được 190Mb dễ dàng trong vài giây.

Nhưng điều này không có nghĩa là bạn có vấn đề với quản lý bộ nhớ.

Lời khuyên tốt nhất tôi có thể đưa ra là tuân theo các hướng dẫn và thực tiễn tốt nhất, sử dụng các thư viện hàng đầu để tải hình ảnh (Glide, Picasso) và bạn sẽ ổn.


Nhưng nếu bạn cần điều chỉnh một cái gì đó và bạn thực sự cần biết bạn có thể phân bổ bao nhiêu bộ nhớ theo cách thủ công, bạn có thể lấy tổng bộ nhớ trống và tính một phần được xác định trước (tính theo%) trong số đó. Trong trường hợp của tôi, tôi cần lưu trữ những bức ảnh được giải mã vào bộ nhớ vì vậy tôi không cần giải mã chúng mỗi khi người dùng trượt qua danh sách.

Đối với mục đích này, bạn có thể sử dụng sẵn sàng để sử dụng lớp LruCache . Đó là một lớp bộ đệm tự động theo dõi lượng bộ nhớ mà các đối tượng của bạn phân bổ (hoặc số lượng phiên bản) và loại bỏ cái cũ nhất để giữ gần đây theo lịch sử sử dụng của chúng. Đây là một hướng dẫn tuyệt vời về cách sử dụng nó.

Trong trường hợp của tôi, tôi đã tạo 2 trường hợp lưu trữ: cho ngón tay cái và tệp đính kèm. Làm cho chúng tĩnh với quyền truy cập singleton để chúng có sẵn trên toàn cầu trong ứng dụng.

lớp bộ đệm:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

Đây là cách tôi tính toán RAM miễn phí có sẵn và tôi có thể cắn được bao nhiêu:

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

Và đây là cách tôi sử dụng nó trong Bộ điều hợp để có được hình ảnh được lưu trong bộ nhớ cache:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

và cách tôi đặt nó vào bộ đệm trong luồng nền (AsyncTask thông thường):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

Ứng dụng của tôi nhắm mục tiêu API 19+ để các thiết bị không cũ và các phần RAM có sẵn này đủ tốt để lưu vào bộ đệm trong trường hợp của tôi (1% và 3%).

Sự thật thú vị: Android không có bất kỳ API hoặc các bản hack nào khác để có được dung lượng bộ nhớ được phân bổ cho ứng dụng của bạn, nó được tính toán nhanh chóng dựa trên các yếu tố khác nhau.


PS Tôi đang sử dụng trường lớp tĩnh để giữ bộ đệm nhưng theo hướng dẫn mới nhất của Android, nên sử dụng thành phần kiến ​​trúc ViewModel cho mục đích đó.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.