在Android中检测应用程序堆大小

hpi*_*que 143 memory heap android heap-memory

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

我听说有一个功能可以在SDK的更高版本中执行此操作.无论如何,我正在寻找适合1.5及以上的解决方案.

Car*_*arl 443

有两种方法可以考虑您的短语"应用程序堆大小可用":

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

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

存在用于确定上述每个的不同方法.

对于上面的第1项: maxMemory()

可以调用(例如,在您的主要活动的onCreate()方法中),如下所示:

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
Run Code Online (Sandbox Code Playgroud)

此方法告诉您允许应用程序使用的堆总字节数.

对于上面的第2项: getMemoryClass()

可以调用如下:

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

这个方法告诉你应用程序应该使用多少兆字节的堆,如果它想要正确地尊重当前设备的限制,以及其他应用程序运行的权限而不是被反复强制进入/ 循环,因为它们是粗鲁的当您的大象应用程序在Android按摩浴缸中洗澡时,内存已经消失.onStop()onResume()

据我所知,这个区别没有明确记录,但我已经在五种不同的Android设备上测试了这个假设(见下文),并且我已经确认这是一个正确的解释.

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

两种方法可以分散的唯一情况(我知道)是在运行Android版本(如CyanogenMod)的root设备上,它允许用户手动选择每个应用程序应允许的堆大小.例如,在CM中,此选项显示在"CyanogenMod设置"/"性能"/"VM堆大小"下.

注意:如果您选择的值小于设备的正常值,请注意手动设置此值可能会使您的系统失效.

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

  • G1:
    • VM堆大小设置为16MB:
      • maxMemory:16777216
      • getMemoryClass:16
    • VM堆大小设置为24MB:
      • maxMemory:25165824
      • getMemoryClass:16
  • Moto Droid:
    • VM堆大小设置为24MB:
      • maxMemory:25165824
      • getMemoryClass:24
    • VM堆大小设置为16MB:
      • maxMemory:16777216
      • getMemoryClass:24
  • Nexus One:
    • VM堆大小设置为32MB:
      • maxMemory:33554432
      • getMemoryClass:32
    • VM堆大小设置为24MB:
      • maxMemory:25165824
      • getMemoryClass:32
  • Viewsonic GTab:
    • VM堆大小设置为32:
      • maxMemory:33554432
      • getMemoryClass:32
    • VM堆大小设置为64:
      • maxMemory:67108864
      • getMemoryClass:32

除了上述内容之外,我还在运行Ice Cream Sandwich的Novo7 Paladin平板电脑上进行了测试.这本质上是ICS的库存版本,除了我通过一个不替换整个操作系统的简单过程来植根平板电脑,特别是没有提供允许手动调整堆大小的接口.

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

  • NOVO7
    • maxMemory:62914560
    • getMemoryClass:60

另外(以下评论中每个基肖尔):

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

并且(根据akauppi的评论):

  • 三星Galaxy Core Plus
    • maxMemory :(未在评论中指定)
    • getMemoryClass:48
    • largeMemoryClass:128

根据cmcromance的评论:

  • Galaxy S3(Jelly Bean)大堆
    • maxMemory:268435456
    • getMemoryClass:64

并且(根据腾讯的评论):

  • LG Nexus 5(4.4.3)正常
    • maxMemory:201326592
    • getMemoryClass:192
  • LG Nexus 5(4.4.3)大堆
    • maxMemory:536870912
    • getMemoryClass:192
  • Galaxy Nexus(4.3)正常
    • maxMemory:100663296
    • getMemoryClass:96
  • Galaxy Nexus(4.3)大堆
    • maxMemory:268435456
    • getMemoryClass:96
  • Galaxy S4 Play Store Edition(4.4.2)正常
    • maxMemory:201326592
    • getMemoryClass:192
  • Galaxy S4 Play Store Edition(4.4.2)大堆
    • maxMemory:536870912
    • getMemoryClass:192

其他设备

  • 华为Nexus 6P(6.0.1)正常
    • maxMemory:201326592
    • getMemoryClass:192

我没有测试过使用专门给Android这两个方法:由于蜂窝纸板可largeHeap ="真"清单的选项,但由于cmcromance和腾讯,我们确实有一些样品largeHeap值,如上报道.

我的预期(这似乎是由上述largeHeap数字来支持)将是这个选项将有类似于通过扎根OS手动设置堆的效果-即,它会提高的价值maxMemory(),同时留下getMemoryClass()一个人.还有另一种方法getLargeMemoryClass(),它使用largeHeap设置指示应用程序允许的内存量.getLargeMemoryClass()的文档指出,"大多数应用程序不需要这么多内存,而应该保持getMemoryClass()限制."

如果我猜对了,那么使用该选项将具有与使用通过root操作系统增加堆的用户可用空间相同的好处(和危险)(即,如果您的应用使用额外的内存,它可能不会与用户同时运行的任何其他应用程序一样好玩.

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

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

我自己的实际经验是在G1(内存类为16)上,如果我手动选择24MB作为堆大小,即使我的内存使用量允许向20MB漂移,我也可以毫无错误地运行(可能它可以高达24MB,虽然我没试过这个).但是,由于我自己的应用程序的贪婪,其他类似的大型应用程序可能会从内存中刷新.而且,相反,如果用户将这些其他高维护应用程序带到前台,我的应用程序可能会从内存中刷新.

所以,你不能超过指定的内存量maxMemory().并且,您应该尽量保持在指定的限制范围内getMemoryClass().一种方法是,如果所有其他方法都失败,可能会以节省内存的方式限制此类设备的功能.

最后,如果您计划超过指定的兆字节数getMemoryClass(),我的建议是在保存和恢复应用程序状态时长时间努力工作,以便在发生onStop()/ onResume()循环时用户的体验几乎不会中断.

在我的情况下,出于性能原因,我将我的应用程序限制为运行2.2及更高版本的设备,这意味着几乎所有运行我的应用程序的设备都将具有24或更高的memoryClass.因此,我可以设计占用高达20MB的堆,并且非常自信我的应用程序将与用户可能同时运行的其他应用程序一起使用.

但总会有一些有根的用户将2.2或以上版本的Android加载到较旧的设备上(例如,G1).当你遇到这样的配置时,理想情况下,你应该减少你的记忆使用,即使maxMemory()你告诉你你可以远远超过getMemoryClass()告诉你应该瞄准的16MB .如果您无法可靠地确保您的应用程序符合预算,那么至少要确保onStop()/ onResume()无缝地工作.

getMemoryClass()如上面的Diane Hackborn(hackbod)所示,只能返回到API级别5(Android 2.0),因此,正如她所建议的那样,您可以假设运行早期版本操作系统的任何设备的物理硬件都是设计的最佳地支持占用堆空间不超过16MB的应用程序.

相比之下,maxMemory()根据文档,可以一直回到API级别1 maxMemory(),在2.0之前的版本上,可能会返回16MB的值,但我确实在我的(很晚以后)CyanogenMod版本中看到了用户可以选择低至12MB的堆值,这可能会导致较低的堆限制,因此我建议您继续测试该maxMemory()值,即使对于2.0之前的OS版本也是如此.如果您需要超过maxMemory()指示允许,您甚至可能不得不拒绝在此值设置为低于16MB的情况下运行.

  • 只为Android按摩浴缸中的大象浴+1:P (52认同)
  • @Carl您好卡尔,感谢您的精彩帖子.我用JellyBean在Galaxy S3上测试了选项,android:largeHeap ="true".这是结果.[maxMemory:256.0MB,memoryClass:64MB](maxMemory为64MB,没有largeheap选项) (2认同)

hac*_*bod 20

官方API是:

这是在2.0中引入的,其中出现了更大的存储设备.您可以假设运行早期版本操作系统的设备正在使用原始内存类(16).


Nei*_*aft 13

Debug.getNativeHeapSize()我会思考,会做的伎俩.不过,自1.0以来它一直存在.

Debug班有很多的跟踪分配和其他性能方面的问题很大的方法.此外,如果您需要检测低内存情况,请查看Activity.onLowMemory().

  • 我对此很新,但我不认为本机堆与问题所引用的app(Dalvik)堆相同.本机堆为位图数据提供支持,位图数据由本机代码分配,而app堆包含Java应用程序数据.我有兴趣了解本机堆是根据应用程序堆的限制计算的,而在3.0之后,实际上会在应用程序堆上进行分配.Diane Hackborn(hackbod)在这里发表了关于这个话题的帖子:http://stackoverflow.com/questions/1945142/bitmaps-in-android但是即使对于3.0,app堆上也有非"原生"数据. (2认同)

and*_*per 13

这是你如何做到的:

获取应用程序可以使用的最大堆大小:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();
Run Code Online (Sandbox Code Playgroud)

获取您的应用当前使用的堆数:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();
Run Code Online (Sandbox Code Playgroud)

获取您的应用现在可以使用多少堆(可用内存):

long availableMemory=maxMemory-usedMemory;
Run Code Online (Sandbox Code Playgroud)

并且,为了很好地格式化它们,您可以使用:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 
Run Code Online (Sandbox Code Playgroud)


fhu*_*cho 6

这将返回最大堆大小(以字节为单位):

Runtime.getRuntime().maxMemory()
Run Code Online (Sandbox Code Playgroud)

我正在使用 ActivityManager.getMemoryClass() 但在 CyanogenMod 7 上(我没有在其他地方测试过),如果用户手动设置堆大小,它会返回错误的值。