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

时间:2013-09-07 16:40:08

标签: android memory memory-management out-of-memory android-memory

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

我想知道的是:

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

最重要的是:

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

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

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

是什么让我非常好奇:

这两个限制都非常低。

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

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

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

4 个答案:

答案 0 :(得分:113)

  

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

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

  

Android版本之间是否有任何差异?

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

  

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

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

  

在确定应用可以使用多少RAM时会考虑哪些“因素”?

我不知道“边缘因素”是什么意思。

  

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

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

  

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

您认为该应用的作者知道他在做什么。考虑到memory usage of an app is difficult for a core Android engineer to determine,我不认为有问题的应用程序必然会提供特别准确的结果。

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

  

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

请记住,Android垃圾收集器不是压缩垃圾收集器。例外情况应该是CouldNotFindSufficientlyLargeBlockOfMemoryException,但这可能被认为过于冗长。 OutOfMemoryException表示您无法分配您请求的阻止,而不是您完全耗尽了您的堆。

答案 1 :(得分:12)

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

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

答案 2 :(得分:9)

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

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

另外here is a great article在官方文档中也提供了有关如何使用Memory Profiler的详细说明,这可以使您对内存管理有更深入的了解。

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

enter image description here

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

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

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


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

为此,您可以使用随时可用的LruCache class。它是一个缓存类,它会自动跟踪对象分配的内存量(或实例数),并根据其使用历史记录删除最旧的以保持最新状态。 Here is很棒的使用教程。

就我而言,我创建了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或其他黑客来获取分配给您的应用程序的内存量,它是根据各种因素动态计算得出的。


P.S。我正在使用静态类字段来保存缓存,但是根据最新的Android指南,建议为此目的使用ViewModel architecture component

答案 3 :(得分:0)

没有任何限制了。为什么要在那里?请记住,Android历史上是来自嵌入式设备世界的,每个应用程序都有明确的简单任务要做,通常根本不允许使用动态内存。

它不被认为是通用系统。我们仍然可以看到许多古代的设计工件,这些工件在“真实计算机”上从来没有用过,这是iOS具有比Android更好的应用程序的原因,它设计得更好,更容易为用户驱动的任务编程

在应用程序设计中,重要的是您的活动对“ onLowMemory”信号反应良好。