如何以编程方式检测Android应用程序可用的应用程序堆大小?

我听说在SDK的更高版本中有一个函数可以做到这一点.无论如何,我正在寻找适用于1.5及以上版本的解决方案.

推荐答案

对于您的短语"应用程序堆大小可用",有两种思考方式:

  1. 在触发硬错误之前,我的应用程序可以使用多少堆?和

  2. 考虑到Android操作系统版本和用户设备硬件的限制,我的应用程序使用了多少heap should

有不同的方法来确定上述各项.

以上第1项:maxMemory()

可以按如下方式调用(例如,在主活动的onCreate()方法中):

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

此方法告诉您的应用程序总共要使用多少堆bytes,即allowed.

以上第2项:getMemoryClass()

可以按如下方式调用:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

这个方法告诉你,如果你的应用程序should想要适当尊重当前设备的限制,以及其他应用程序的运行权限,而不必反复被迫进入onStop()/onResume()循环,因为当你的elephantine应用程序在Android按摩浴缸中洗澡时,它们会被粗暴地从内存中冲出,那么你的应用程序should大约会使用多少堆.

据我所知,这种区别并没有明确的记录,但我已经在五种不同的安卓设备(见下文)上测试了这一假设,并以我自己的满意程度证实了这是一种正确的解释.

对于Android的普通版本,maxMemory()通常会返回与getMemoryClass()相同的兆字节数(即,大约是后者的一百万倍).

这两种方法唯一可能出现分歧的情况(我知道)是在运行Android版本(如CyanogenMod)的根设备上,该版本允许用户手动确定每个应用程序允许的堆大小.例如,在CM中,该选项出现在"CyanogenMod设置"/"性能"/"VM堆大小"下.

注意:请注意,手动设置此值可能会使您的系统变得混乱,特别是当您 Select 的值小于设备的正常值时.

以下是我的测试结果,显示了运行CyanogenMod的四个不同设备的maxMemory()getMemoryClass()返回的值,每个设备使用两个不同(手动设置)的堆值:

  • G1:
    • VM堆大小设置为16MB时:
    • With VM Heap Size set to 24MB:
      • 最大内存:25165824
      • getMemoryClass:16
  • Moto Droid:
    • With VM Heap Size set to 24MB:
      • 最大内存:25165824
      • getMemoryClass:24
    • With VM Heap Size set to 16MB:
      • 最大内存:16777216
      • getMemoryClass:24
  • Nexus One:
    • 将VM堆大小设置为32MB时:
      • 最大内存:33554432
      • getMemoryClass:32
    • With VM Heap size set to 24MB:
      • 最大内存:25165824
      • getMemoryClass:32
  • Viewsonic GTab:
    • With VM Heap Size set to 32:
      • maxMemory:33554432
      • getMemoryClass:32
    • With VM Heap Size set to 64:
      • maxMemory:67108864
      • getMemoryClass:32

除上述内容外,我还在Novo7 Paladin平板电脑上测试了冰淇淋三明治.

对于该设备,以下是结果:

  • Novo7
    • 最大内存:62914560
    • getMemoryClass:60

另(根据基肖尔在下面的 comments 中的说法):

  • HTC One X
    • maxMemory:67108864
    • getMemoryClass:64

以及(根据阿卡皮的 comments ):

  • 三星Galaxy Core Plus

根据Cmcromance的 comments :

  • Galaxy S3 (Jelly Bean) large heap
    • maxMemory:268435456
    • getMemoryClass:64

以及(根据腾讯的 comments ):

  • LG Nexus 5(4.4.3)正常
  • LG Nexus 5 (4.4.3) large heap
    • maxMemory:536870912
    • getMemoryClass:192
  • Galaxy Nexus(4.3)正常
    • 最大内存:100663296
    • getMemoryClass:96
  • Galaxy Nexus (4.3) large heap
    • maxMemory:268435456
    • getMemoryClass:96
  • Galaxy S4 Play Store Edition (4.4.2) normal
    • maxMemory:201326592
    • getMemoryClass:192
  • Galaxy S4 Play Store Edition (4.4.2) large heap
    • maxMemory:536870912
    • getMemoryClass:192

其他设备

  • Huawei Nexus 6P (6.0.1) normal
    • maxMemory:201326592
    • getMemoryClass:192

我还没有使用自蜂巢以来提供的特殊安卓:largeHeap="true" list 选项测试这两种方法,但多亏了cmcromance和腾讯,我们确实有一些样本largeHeap值,如上所述.

我的expectation(上面的大堆号似乎支持它)是,这个选项的效果类似于通过根OS手动设置堆,也就是说,它会在不使用getMemoryClass()的情况下提高maxMemory()的值.还有另一个方法getLargeMemoryClass(),它指示使用largeHeap设置的应用程序允许的内存量.getLargeMemoryClass()的文档中指出,"大多数应用程序不应该需要这么多内存,而是应该遵守getMemoryClass()的限制."

如果我猜对了,那么使用该选项的好处(和危险)与使用通过根操作系统增加堆的用户提供的空间的好处(也就是说,如果你的应用程序使用额外的内存,那么它可能不会与用户同时运行的任何其他应用程序一起很好地发挥作用)相同.

注意,内存类显然不需要是8MB的倍数.

从上面我们可以看到,对于给定的设备/操作系统配置,getMemoryClass()结果是不变的,而当用户设置不同的堆时,maxMemory()值会发生变化.

我自己的实际经验是,在G1(它的内存类为16)上,如果我手动 Select 24MB作为堆大小,即使允许内存使用量上升到20MB(虽然我还没有try 过,但它可能高达24MB),我也可以正确地运行.但其他类似的大型应用程序可能会因为我自己的应用程序的小巧玲珑而被从内存中清除.相反,如果用户将这些其他高维护应用程序带到前台,则my个应用程序可能会从内存中清除.

因此,不能超过maxMemory()指定的内存量.而且,你应该保持trygetMemoryClass()规定的范围内.如果其他方法都失败了,一种方法可能是以节省内存的方式限制此类设备的功能.

最后,如果你确实计划超过getMemoryClass()中指定的兆字节数,我的建议是长时间努力保存和恢复你的应用程序的状态,这样,如果出现onStop()/onResume()周期,用户的体验几乎是不间断的.

在我的例子中,出于性能的原因,我将我的应用程序限制在运行2.2或更高版本的设备上,这意味着几乎所有运行我的应用程序的设备都将拥有24或更高的内存类别.因此,我可以设计占用高达20MB的堆,并且非常有信心我的应用程序将与用户可能同时运行的其他应用程序很好地配合使用.

但总会有一些根深蒂固的用户将2.2或更高版本的安卓系统加载到较旧的设备(例如G1)上.当你遇到这样的配置时,理想情况下,你应该减少你的内存使用,即使maxMemory()告诉你你可以比16MB高很多,getMemoryClass()告诉你你的目标是should.如果你不能可靠地确保你的应用程序在预算范围内运行,那么至少要确保onStop()/onResume()能够无缝工作.

正如上面Diane Hackborn(hackbod)所指出的,getMemoryClass()只在API级别5(Android 2.0)下可用,因此,正如她建议的那样,你可以假设运行早期版本操作系统的任何设备的物理硬件都是为了最佳支持占用不超过16MB堆空间的应用而设计的.

相比之下,根据文档,maxMemory()可以一直追溯到API级别1.在2.0之前的版本上,maxMemory()可能会返回16MB的值,但我看到在我(更晚的)CyanogenMod版本中,用户可以 Select 低至12MB的堆值,这可能会导致较低的堆限制,因此我建议您继续测试maxMemory()的值,即使对于2.0之前的OS版本也是如此.如果这个值设置得甚至低于16MB,并且需要超过maxMemory()个指示,那么您甚至可能不得不拒绝运行.

Android相关问答推荐

将HTML约束布局转换为Jetpack编写约束布局-链样式、偏差

为什么使用. DeliverveAsState()时会出现空指针异常?

Jetpack编写Lazy列滑动删除动画不顺利结束

list 合并失败,AGP 8.3.0

Material 3的MaterialSwitch默认大小太大了?如何使它变小?

具有数据库和升级潜力的移动应用程序开发(Android)供朋友使用

Kotlin 协程、 retrofit 、android

延时kotlin中时分秒的使用方法

Jetpack compose (Glance) 小部件在加载位图图像后不会重新组合

Android Studio:按下前缀键:切换 Logcat 格式

视觉转换后获取文本

Android apk 不工作

是否可以在 Kotlin 中为 mutableStateOf() 设置自定义设置器

如何在组件之间导航

LazyColumn 单选中的状态提升. Jetpack compose

如何在最后一个可见项目之后计算惰性列中的空白空间

运行一次 kotlin 流,但在下游收到两次

如何在包含 Jetpack Compose 内容的布局中使用权重

复用 RecyclerView 适配器,避免不必要的 API 调用

Android Material Date Range Picker - 如何仅更改所选范围日期的文本 colored颜色 ?