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

Phi*_*oda 140 memory android memory-management out-of-memory android-memory

我对这个关于Android操作系统内存管理的问题很好奇,所以我希望对这个主题有一个非常详细的答案.

我想知道的是:

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

最重要的是:

  • 当系统确定应用程序在运行时可以使用多少RAM时(假设每个应用程序的内存最大值不是静态数字),它是什么/它取决于什么

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

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

是什么让我很好奇:

这两个限制都非常低.

我刚刚下载了Android任务管理器来检查我的设备RAM.我注意到有些应用程序使用大约40-50兆字节的RAM,这比上面提到的最大RAM使用量(比如说32 MB)要多得多.那么Android如何确定应用程序可以使用多少RAM?应用程序如何超出此限制?

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

免责声明:我不以任何方式与Android任务管理器应用程序相关联.

Com*_*are 118

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

这取决于设备.getMemoryClass()onActivityManager将为您提供运行代码的设备的值.

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

是的,就多年来操作系统要求的增加而言,设备必须进行调整才能匹配.

有关设备制造商的差异吗?

是的,就制造商制造设备而言,尺寸因设备而异.

在确定应用程序可以使用多少RAM时,会考虑哪些"因素"?

我不知道"边缘因素"是什么意思.

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

那是对的.屏幕分辨率是一个重要的决定因素,因为较大的分辨率意味着较大的位图,因此平板电脑和高分辨率手机的价值往往更高.例如,您将看到具有48MB堆的设备,如果有高于此值的值,我不会感到惊讶.

应用程序如何超出此限制?

您假设该应用程序的作者知道他正在做什么.考虑到核心Android工程师很难确定应用程序的内存使用情况,我不会认为有问题的应用程序必然会提供特别准确的结果.

话虽这么说,本机代码(NDK)不受堆限制.而且,从Android 3.0开始,应用程序可以请求"大堆",通常在数百MB的范围内,但对于大多数应用程序而言,这被认为是糟糕的形式.

此外,我注意到当使用大约30-40兆字节时,我的一些应用程序崩溃了OutOfMemoryException.

请记住,Android垃圾收集器不是压缩垃圾收集器.真的应该是例外CouldNotFindSufficientlyLargeBlockOfMemoryException,但这可能被认为过于冗长.OutOfMemoryException意味着您无法分配您请求的块,而不是您完全耗尽了您的堆.


Kir*_*zin 15

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

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

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

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

在此处输入图片说明

通常,应用程序以50Mb的RAM分配开始,但是当您开始在内存中加载一些照片时,应用程序会立即跳至90Mb。当您使用带有预加载照片的ViewPager(每张3,5Mb)打开“活动”时,可以在几秒钟内轻松获得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;
}
}
Run Code Online (Sandbox Code Playgroud)

这是我计算可用空闲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);
}
Run Code Online (Sandbox Code Playgroud)

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

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);
Run Code Online (Sandbox Code Playgroud)

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

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 
Run Code Online (Sandbox Code Playgroud)

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

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


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


小智 12

每个应用的内存限制取决于屏幕大小和Android版本:https://drive.google.com/file/d/0B7Vx1OvzrLa3Y0R0X1BZbUpicGc/view?usp=sharing

来源:Android兼容性下载http://source.android.com/compatibility/downloads.html ; 兼容性定义文档(CDD),部分虚拟机兼容性或运行时兼容性

  • 驱动器 URL 请求访问权限 (11认同)