如何以编程方式检测Android应用程序可用的应用程序堆大小?
我听说在SDK的更高版本中有一个函数可以做到这一点.无论如何,我正在寻找适用于1.5及以上版本的解决方案.
如何以编程方式检测Android应用程序可用的应用程序堆大小?
我听说在SDK的更高版本中有一个函数可以做到这一点.无论如何,我正在寻找适用于1.5及以上版本的解决方案.
对于您的短语"应用程序堆大小可用",有两种思考方式:
在触发硬错误之前,我的应用程序可以使用多少堆?和
考虑到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()
返回的值,每个设备使用两个不同(手动设置)的堆值:
除上述内容外,我还在Novo7 Paladin平板电脑上测试了冰淇淋三明治.
对于该设备,以下是结果:
另(根据基肖尔在下面的 comments 中的说法):
以及(根据阿卡皮的 comments ):
根据Cmcromance的 comments :
以及(根据腾讯的 comments ):
其他设备
我还没有使用自蜂巢以来提供的特殊安卓: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()
指定的内存量.而且,你应该保持try在getMemoryClass()
规定的范围内.如果其他方法都失败了,一种方法可能是以节省内存的方式限制此类设备的功能.
最后,如果你确实计划超过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()
个指示,那么您甚至可能不得不拒绝运行.