应用程序可以使用的最大RAM数量是多少?


145

我对这个与Android操作系统内存管理有关的问题非常好奇,因此我希望就该主题提供一个非常详细的答案。

我想知道的是:

  • Android应用程序(不是系统应用程序)可以使用的最大内存量兆字节 / 占总RAM的百分比)是多少?
  • Android版本之间有什么区别吗?
  • 关于设备制造商有什么区别吗?

最重要的是:

  • 什么被视为/ 这是什么取决于当它涉及到系统中确定多少内存的应用程序可以在运行时使用(假设每个应用程序的内存最大是不是一个静态的数字)?

到目前为止(截至2013年)我所听到的:

  • 早期的Android设备的每个应用上限为16MB
  • 后来这个上限增加到24MB或32MB

是什么让我非常好奇:

这两个限制都非常低。

我刚刚下载了Android任务管理器,以检查设备的RAM。我注意到的是,有些应用程序使用大约40-50 MB的RAM,这比上面提到的最大RAM使用量(例如32 MB)要明显得多。那么Android如何确定一个应用可以使用多少RAM?应用程序怎么可能超过该限制?

此外,我注意到当使用大约30-40 MB时,我的一些应用程序崩溃了(被系统杀死了?),并带有OutOfMemoryException。另一方面,一段时间后(可能是由于内存泄漏),我的手机上使用的应用程序使用的内存为100 MB以上并且不会崩溃或消失。因此,在确定可以保留多少RAM时,显然还取决于应用程序本身。这怎么可能?(我使用具有768 MB RAM的HTC One S进行了测试)

免责声明:我不以任何方式与Android Task Manager应用关联。

Answers:


119

Android应用程序(非系统应用程序)可以使用的最大内存量(以兆字节为单位/占总RAM的百分比)是多少?

这因设备而异。getMemoryClass()onActivityManager将为您提供运行代码的设备的值。

Android版本之间有什么区别吗?

是的,这些年来OS要求不断增加,并且设备必须进行调整以匹配。

关于设备制造商是否存在差异?

是的,只要制造商制造设备,并且大小随设备而异。

在确定应用程序可以使用多少RAM时,要考虑哪些“附带因素”?

我不知道“附带条件”是什么意思。

早期的设备每个应用程序的上限为16MB;后来的设备增加到24MB或32MB

没错。屏幕分辨率是一个重要的决定因素,因为更大的分辨率意味着更大的位图,因此平板电脑和高分辨率手机将倾向于具有更高的值。例如,您将看到具有48MB堆的设备,并且如果有更高的值,我也不会感到惊讶。

应用程序怎么可能超过该限制?

您假设该应用程序的作者知道他在做什么。考虑到Android核心工程师难以确定应用程序的内存使用情况,因此我不认为所讨论的应用程序必须提供特别准确的结果。

话虽如此,本机代码(NDK)不受堆限制。而且,从Android 3.0开始,应用程序可以请求“大堆”,通常在数百MB范围内,但是对于大多数应用程序来说,这是较差的形式。

此外,我注意到我的某些应用在使用大约30-40 MB时崩溃,并发生OutOfMemoryException。

请记住,Android垃圾收集器不是压缩垃圾收集器。确实应该有例外CouldNotFindSufficientlyLargeBlockOfMemoryException,但这可能被认为太罗y了。OutOfMemoryException意味着您不能分配所请求的块,而不是您已经用尽了整个堆。


我对桌子不了解,我有Xperia X mobile,它的分辨率约为1080 x 1920,这是大分辨率,而另一台设备Samsung Tab 4的分辨率是800 x 1280,所以它占用了相同的内存,请指导我,因为移动设备自带3GB RAM和选项卡随附1.5GB RAM,因此平板电脑会因为大屏幕而占用较大的内存?
拉胡尔·曼达里亚

@RahulMandaliya:对不起,但我不理解您的担心或与该问题的关系。您可能希望打开一个单独的堆栈溢出问题,在其中详细说明您的关注点。
CommonsWare

15

到了2018年底,情况发生了变化。

首先:运行您的应用程序,然后在Android Studio中打开“ Android Profiler”标签。您会看到它消耗了多少内存,您会感到惊讶,但是它可以分配很多RAM。

另外,这是官方文档中的一篇精彩文章,其中包含有关如何使用Memory Profiler的详细说明,它可以使您对内存管理有更深入的了解。

但是在大多数情况下,常规的Android Profiler就足够了。

在此处输入图片说明

通常,一个应用程序以50Mb的RAM分配开始,但是当您开始在内存中加载一些照片时会立即跳至90Mb。使用带有预加载照片的ViewPager(每张照片3Mb)打开“活动”时,您可以在几秒钟内轻松获得190Mb。

但这并不意味着您在内存管理方面存在问题。

我能提供的最佳建议是遵循准则和最佳实践,使用顶级库进行图像加载(Glide,Picasso),您会没事的。


但是,如果您需要调整某些内容,并且确实需要知道可以手动分配多少内存,则可以获得总的可用内存并从中计算出预定部分(以%为单位)。就我而言,我需要将解密的照片缓存在内存中,因此不需要每次用户在列表中滑动时都将其解密。

为此,您可以使用立即可用的LruCache类。这是一个缓存类,可自动跟踪对象分配的内存量(或实例数),并根据使用历史记录删除最旧的以保持最新状态。 这是有关如何使用它的很棒的教程。

就我而言,我创建了2个缓存实例:用于拇指和附件。通过单例访问使它们静态,因此在整个应用程序中全局可用。

缓存类:

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;
}
}

这是我如何计算可用的可用RAM以及可以从中抽出多少内存:

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);
}

这就是我在适配器中使用它来获取缓存图像的方式:

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

以及如何将其设置为后台线程的缓存(常规AsyncTask):

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

我的应用程序以API 19+为目标,因此设备不是旧的,在我的情况下,这些可用RAM的这些部分足以缓存(分别为1%和3%)。

有趣的事实: Android没有任何API或其他黑客来获取分配给您的应用程序的内存量,它是根据各种因素动态计算的。


PS我正在使用静态类字段来保存缓存,但是根据最新的Android指南,建议为此目的使用ViewModel体系结构组件


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.