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

我听说在更高版本的SDK中有一个函数可以执行此操作。无论如何,我正在寻找适用于1.5及更高版本的解决方案。

最佳答案

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

  • 在触发硬错误之前,我的应用程序可以使用多少堆?和
  • 考虑到Android OS版本和用户设备硬件的限制,我的应用程序应使用多少堆?

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

    对于上述项目1:maxMemory()
    可以按以下方式调用(例如,在您的主要 Activity 的onCreate()方法中):
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
    

    此方法告诉您应用程序允许使用多少总堆字节。

    对于上述第2项:getMemoryClass()
    可以如下调用:
    ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    int memoryClass = am.getMemoryClass();
    Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
    

    此方法告诉您,如果应用程序要适当尊重当前设备的限制,以及其他应用程序在不被反复强制进入onStop()/onResume()周期的情况下运行的权利,则大约应使用多少兆字节的堆。当您的大象应用在Android按摩浴缸中洗澡时,会被无理地冲出内存。

    据我所知,这种区别尚无明确记载,但我已经在五种不同的Android设备(见下文)上验证了这一假设,并令我满意的是,这是正确的解释。

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

    这两种方法可以发生分歧的唯一情况(据我所知)是在运行Android版本(例如CyanogenMod)的 Root设备上进行的,该设备允许用户手动选择每个应用程序应允许的堆大小。例如,在CM中,此选项显示在“CyanogenMod设置”/“性能”/“VM堆大小”下。

    注意:请注意,手动设置此值可以改善您的系统,特别是如果您选择的值小于设备的正常值。

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

    vm_heap大小设置为16MB的
  • :
  • maxMemory:16777216
  • getMemoryClass:16
  • vm_heap大小设置为24MB的
  • :
  • maxMemory:25165824
  • getMemoryClass:16
  • Moto Droid:

    vm_heap大小设置为24MB的
  • :
  • maxMemory:25165824
  • getMemoryClass:24
  • vm_heap大小设置为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的普通版本,只是我通过一个简单的过程使平板电脑 Root ,而不是替换整个OS,特别是它不提供允许手动调整堆大小的界面。

    对于该设备,结果如下:
  • Novo7
  • maxMemory:62914560
  • getMemoryClass:60

  • 另外(根据Kishore在下面的评论中):
  • HTC One X
  • maxMemory:67108864
  • getMemoryClass:64

  • 并且(根据akauppi的评论):
  • 三星Galaxy Core Plus
  • maxMemory :(未在注释中指定)
  • getMemoryClass:48个
  • largeMemoryClass:128

  • 根据cmcromance的评论:
  • Galaxy S3(果冻 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商店版(4.4.2)正常
  • maxMemory:201326592
  • getMemoryClass:192
  • Galaxy S4 Play商店版(4.4.2)大堆
  • maxMemory:536870912
  • getMemoryClass:192

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

  • 我没有使用自Honeycomb以来可用的特殊android:largeHeap =“true” list 选项来测试这两种方法,但是由于cmcromance和腾讯,我们确实有一些示例largeHeap值,如上所述。

    我的期望(上面的largeHeap数字似乎支持)是此选项的效果类似于通过根操作系统手动设置堆-即在不保留maxMemory()的情况下提高getMemoryClass()的值。还有另一种方法getLargeMemoryClass(),该方法指示使用largeHeap设置的应用程序允许多少内存。 getLargeMemoryClass()的文档指出,“大多数应用程序不需要此数量的内存,而应保持在getMemoryClass()的限制之内。”

    如果我猜对了,那么使用该选项与使用已通过根操作系统升级堆的用户提供的空间(即,如果您的应用使用了额外的内存,它可能无法与用户同时运行的任何其他应用程序一起很好地播放)。

    请注意,内存类显然不必为8MB的倍数。

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

    我自己的实际经验是,在G1(内存级别为16)上,如果我手动选择24MB作为堆大小,即使允许将内存使用量提高到20MB,我也可以正常运行。最高可达24MB,尽管我还没有尝试过)。但是,由于我自己的应用程序过于笨拙,其他类似的大型应用程序可能会从内存中清除。而且,相反,如果这些其他高维护性应用程序被用户带到前台,则我的应用程序可能会从内存中清除。

    因此,您不能超过maxMemory()指定的内存量。并且,您应尝试保持在getMemoryClass()指定的限制内。如果所有其他方法都失败了,那么这样做的一种方法可能是以节省内存的方式来限制此类设备的功能。

    最后,如果您确实打算超过getMemoryClass()中指定的兆字节数,我的建议是在保存和恢复应用程序状态方面进行长期而艰苦的工作,以便在onStop()/onResume()循环的情况下,用户的体验几乎不会中断发生。

    就我而言,出于性能方面的考虑,我将我的应用程序限制为运行2.2及更高版本的设备,这意味着几乎所有运行我的应用程序的设备的memoryClass都将为24或更高。因此,我可以设计为最多占用20MB的堆,并确信我的应用程序可以与用户可能同时运行的其他应用程序一起很好地运行。

    但是,总会有一些root用户将2.2或更高版本的Android加载到较旧的设备(例如G1)上。遇到这种配置时,理想情况下,即使maxMemory()告诉您可以比getMemoryClass()告诉您应该定位的16MB高得多,也应该减少内存使用。而且,如果您不能可靠地确保您的应用程序能够在该预算范围内运行,则至少要确保onStop()/onResume()无缝运行。

    如上述Diane Hackborn(hackbod)所指示,getMemoryClass()仅可用于API级别5(Android 2.0),因此,正如她所建议的那样,您可以假定运行早期版本OS的任何设备的物理硬件为旨在最佳地支持占用不超过16MB堆空间的应用程序。

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

    关于android - 在Android中检测应用程序堆大小,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2630158/

    10-10 18:14