【问题标题】:What is the maximum amount of RAM an app can use?应用程序可以使用的最大 RAM 量是多少?
【发布时间】:2013-09-11 14:29:09
【问题描述】:

我对这个关于Android操作系统的内存管理的问题很好奇,所以我希望能得到一个关于这个话题的相当详细的答案。

我想知道的:

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

最重要的是:

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

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

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

是什么让我非常好奇:

这两个限制都非常低。

我最近刚刚下载了Android Task Manager 来检查我的设备内存。我注意到有些应用程序使用了大约 40-50 MB 的 RAM,这显然比提到的最大 RAM 使用量(比如说 32 MB)要多。那么,Android 是如何确定应用程序可以使用多少 RAM 的呢?应用程序怎么可能超过这个限制?

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

免责声明:我与 Android 任务管理器应用没有任何关联。

【问题讨论】:

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


    【解决方案1】:

    不再有任何限制,至少如果您使用 NDK。为什么要在那里?请记住,Android 在历史上来自嵌入式设备世界,在这个世界中,每个应用都有明确的简单任务要做,通常根本不允许动态内存使用。

    它不被视为通用系统。我们仍然可以看到很多古代的设计作品,这些作品在“真正的计算机”上从来没有意义,这也是为什么 iOS 拥有比 android 更好的应用程序的原因,它被设计得更好,更容易为用户驱动的任务编程.

    应用设计中的重要一点是您的活动对“onLowMemory”信号反应良好。

    【讨论】:

      【解决方案2】:

      现在,我正在开发一个应用程序,而我正在使用的三星 Ultra S21(即使有 16GB 的可用内存..)也不允许我为这个应用程序使用超过 500MB 的空间,即使使用 android:largeHeap=" true”在 Manifest 中。

      【讨论】:

        【解决方案3】:

        现在是 2018 年底,所以情况发生了变化。

        首先:运行您的应用并在 Android Studio 中打开 Android Profiler 选项卡。 您会看到它消耗了多少内存,您会感到惊讶,但它可以分配大量 RAM。

        官方文档中还有here is a great article,其中包含有关如何使用 Memory Profiler 的详细说明,它可以让您深入了解内存管理。

        但在大多数情况下,您的常规 Android Profiler 对您来说就足够了。

        通常,应用开始时分配的 RAM 为 50Mb,但当您开始在内存中加载一些照片时,它会立即跃升至 90Mb。当您使用带有预加载照片(每张 3.5Mb)的 ViewPager 打开 Activity 时,您可以在几秒钟内轻松获得 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 或其他技巧来获取分配给您的应用程序的内存量,它是根据各种因素动态计算的。


        附:我正在使用静态类字段来保存缓存,但根据最新的 Android 指南,建议为此使用 ViewModel architecture component

        【讨论】:

        • “有趣的事实:Android 没有任何 API 或其他黑客来获取分配给您的应用程序的内存量”这是错误的。当然有,但是在应用程序的 JNI/Linux 层中。 Android (Java) 本身只是一个夸张的 GUI 库。
        【解决方案4】:

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

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

        【讨论】:

        • 驱动器url请求访问权限
        【解决方案5】:

        Android 应用程序(非系统应用程序)可以使用的最大内存量是多少(以 MB 为单位/占总 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 表示您无法分配您请求的块,并不是说您已经完全耗尽了堆。

        【讨论】:

        • 我无法理解表格,我有 Xperia X mobile,其分辨率约为 1080 x 1920,即大分辨率,而另一台设备三星 Tab 4 的分辨率为 800 x 1280,因此占用相同的内存,请指导我,因为手机带有3GB RAM,而tab带有1.5GB RAM,所以平板电脑因为大屏幕而占用大量内存?
        • @RahulMandaliya:我很抱歉,但我不明白你的担忧或它与这个问题有什么关系。您可能希望打开一个单独的 Stack Overflow 问题,详细解释您的担忧。
        猜你喜欢
        • 2010-09-07
        • 2013-04-19
        • 2015-01-04
        • 2018-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多