检测Android中的应用程序堆大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2630158/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect application heap size in Android
提问by hpique
How do you programmatically detect the application heap size available to an Android app?
如何以编程方式检测 Android 应用程序可用的应用程序堆大小?
I heard there's a function that does this in later versions of the SDK. In any case, I'm looking for solution that works for 1.5 and upwards.
我听说在更高版本的 SDK 中有一个函数可以做到这一点。无论如何,我正在寻找适用于 1.5 及更高版本的解决方案。
回答by Carl
There are two ways to think about your phrase "application heap size available":
有两种方法可以考虑您的短语“可用的应用程序堆大小”:
How much heap can my app use before a hard error is triggered? And
How much heap shouldmy app use, given the constraints of the Android OS version and hardware of the user's device?
在触发硬错误之前,我的应用程序可以使用多少堆?和
考虑到 Android 操作系统版本和用户设备硬件的限制,我的应用程序应该使用多少堆?
There is a different method for determining each of the above.
有一种不同的方法来确定上述各项。
For item 1 above: maxMemory()
对于上述第 1 项: maxMemory()
which can be invoked (e.g., in your main activity's onCreate()
method) as follows:
可以按如下方式调用(例如,在您的主要活动的onCreate()
方法中):
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
This method tells you how many total bytesof heap your app is allowedto use.
这个方法告诉你你的应用程序允许使用的堆总字节数。
For item 2 above: getMemoryClass()
对于上述第 2 项: getMemoryClass()
which can be invoked as follows:
可以按如下方式调用:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
This method tells you approximately how many megabytesof heap your app shoulduse if it wants to be properly respectful of the limits of the present device, and of the rights of other apps to run without being repeatedly forced into the onStop()
/ onResume()
cycle as they are rudely flushed out of memory while your elephantine app takes a bath in the Android jacuzzi.
这个方法告诉你你的应用程序应该使用多少兆字节的堆,如果它想要适当地尊重当前设备的限制,以及其他应用程序运行的权利,而不会因为它们粗鲁而反复被迫进入/循环当您的大象应用程序在 Android 按摩浴缸中洗澡时内存不足。onStop()
onResume()
This distinction is not clearly documented, so far as I know, but I have tested this hypothesis on five different Android devices (see below) and have confirmed to my own satisfaction that this is a correct interpretation.
据我所知,这种区别没有明确记录,但我已经在五种不同的 Android 设备上测试了这个假设(见下文),并且我自己满意地确认这是一个正确的解释。
For a stock version of Android, maxMemory()
will typically return about the same number of megabytes as are indicated in getMemoryClass()
(i.e., approximately a million times the latter value).
对于 Android 的股票版本,maxMemory()
通常会返回与 中所示相同数量的兆字节getMemoryClass()
(即,大约是后者值的一百万倍)。
The only situation (of which I am aware) for which the two methods can diverge is on a rooted device running an Android version such as CyanogenMod, which allows the user to manually selecthow large a heap size should be allowed for each app. In CM, for example, this option appears under "CyanogenMod settings" / "Performance" / "VM heap size".
这两种方法唯一不同的情况(我知道)是在运行 Android 版本(如 CyanogenMod)的有根设备上,它允许用户手动选择每个应用程序应允许的堆大小。例如,在 CM 中,此选项出现在“CyanogenMod 设置”/“性能”/“VM 堆大小”下。
NOTE: BE AWARE THAT SETTING THIS VALUE MANUALLY CAN MESS UP YOUR SYSTEM, ESPECIALLY if you select a smaller value than is normal for your device.
注意:请注意,手动设置此值可能会弄乱您的系统,特别是如果您选择的值小于设备的正常值。
Here are my test results showing the values returned by maxMemory()
and getMemoryClass()
for four different devices running CyanogenMod, using two different (manually-set) heap values for each:
下面是我的测试结果示出了由返回的值maxMemory()
和getMemoryClass()
运行的CyanogenMod四种不同的设备,使用两个不同的(手动设定)堆值为每个:
- G1:
- With VM Heap Size set to 16MB:
- maxMemory: 16777216
- getMemoryClass: 16
- With VM Heap Size set to 24MB:
- maxMemory: 25165824
- getMemoryClass: 16
- With VM Heap Size set to 16MB:
- Moto Droid:
- With VM Heap Size set to 24MB:
- maxMemory: 25165824
- getMemoryClass: 24
- With VM Heap Size set to 16MB:
- maxMemory: 16777216
- getMemoryClass: 24
- With VM Heap Size set to 24MB:
- Nexus One:
- With VM Heap size set to 32MB:
- maxMemory: 33554432
- getMemoryClass: 32
- With VM Heap size set to 24MB:
- maxMemory: 25165824
- getMemoryClass: 32
- With VM Heap size set to 32MB:
- Viewsonic GTab:
- With VM Heap Size set to 32:
- maxMemory: 33554432
- getMemoryClass: 32
- With VM Heap Size set to 64:
- maxMemory: 67108864
- getMemoryClass: 32
- With VM Heap Size set to 32:
- G1:
- 将 VM 堆大小设置为 16MB:
- 最大内存:16777216
- getMemoryClass: 16
- 将 VM 堆大小设置为 24MB:
- 最大内存:25165824
- getMemoryClass: 16
- 将 VM 堆大小设置为 16MB:
- 摩托机器人:
- 将 VM 堆大小设置为 24MB:
- 最大内存:25165824
- getMemoryClass: 24
- 将 VM 堆大小设置为 16MB:
- 最大内存:16777216
- getMemoryClass: 24
- 将 VM 堆大小设置为 24MB:
- 连结一:
- 将 VM 堆大小设置为 32MB:
- 最大内存:33554432
- getMemoryClass: 32
- 将 VM 堆大小设置为 24MB:
- 最大内存:25165824
- getMemoryClass: 32
- 将 VM 堆大小设置为 32MB:
- 优派GTab:
- 将 VM 堆大小设置为 32:
- 最大内存:33554432
- getMemoryClass: 32
- 将 VM 堆大小设置为 64:
- 最大内存:67108864
- getMemoryClass: 32
- 将 VM 堆大小设置为 32:
In addition to the above, I tested on a Novo7 Paladin tablet running Ice Cream Sandwich. This was essentially a stock version of ICS, except that I've rooted the tablet through a simple process that does not replace the entire OS, and in particular does not provide an interface that would allow the heap size to be manually adjusted.
除了上述内容,我还在运行 Ice Cream Sandwich 的 Novo7 Paladin 平板电脑上进行了测试。这本质上是一个 ICS 的股票版本,除了我通过一个简单的过程扎根了平板电脑,这个过程不会取代整个操作系统,特别是不提供允许手动调整堆大小的接口。
For that device, here are the results:
对于该设备,结果如下:
- Novo7
- maxMemory: 62914560
- getMemoryClass: 60
- Novo7
- 最大内存:62914560
- getMemoryClass: 60
Also (per Kishore in a comment below):
另外(根据 Kishore 在下面的评论中):
- HTC One X
- maxMemory: 67108864
- getMemoryClass: 64
- 宏达一X
- 最大内存:67108864
- getMemoryClass: 64
And (per akauppi's comment):
并且(根据 akauppi 的评论):
- Samsung Galaxy Core Plus
- maxMemory: (Not specified in comment)
- getMemoryClass: 48
- largeMemoryClass: 128
- 三星 Galaxy Core Plus
- maxMemory:(未在评论中指定)
- getMemoryClass: 48
- 大内存类:128
Per a comment from cmcromance:
根据 cmcromance 的评论:
- Galaxy S3 (Jelly Bean) large heap
- maxMemory: 268435456
- getMemoryClass: 64
- Galaxy S3(果冻豆)大堆
- 最大内存:268435456
- getMemoryClass: 64
And (per tencent's comments):
并且(根据腾讯的评论):
- LG Nexus 5 (4.4.3) normal
- maxMemory: 201326592
- getMemoryClass: 192
- LG Nexus 5 (4.4.3) large heap
- maxMemory: 536870912
- getMemoryClass: 192
- Galaxy Nexus (4.3) normal
- maxMemory: 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
- LG Nexus 5 (4.4.3) 正常
- 最大内存:201326592
- getMemoryClass: 192
- LG Nexus 5 (4.4.3) 大堆
- 最大内存:536870912
- getMemoryClass: 192
- Galaxy Nexus (4.3) 正常
- 最大内存:100663296
- getMemoryClass: 96
- Galaxy Nexus (4.3) 大堆
- 最大内存:268435456
- getMemoryClass: 96
- Galaxy S4 Play 商店版 (4.4.2) 正常
- 最大内存:201326592
- getMemoryClass: 192
- Galaxy S4 Play商店版(4.4.2)大堆
- 最大内存:536870912
- getMemoryClass: 192
Other Devices
其他设备
- Huawei Nexus 6P (6.0.1) normal
- maxMemory: 201326592
- getMemoryClass: 192
- 华为 Nexus 6P (6.0.1) 正常
- 最大内存:201326592
- getMemoryClass: 192
I haven't tested these two methods using the special android:largeHeap="true" manifest option available since Honeycomb, but thanks to cmcromance and tencent we do have some sample largeHeap values, as reported above.
我还没有使用自 Honeycomb 以来可用的特殊 android:largeHeap="true" 清单选项测试这两种方法,但多亏了 cmcromance 和腾讯,我们确实有一些示例 largeHeap 值,如上所述。
My expectation(which seems to be supported by the largeHeap numbers above) would be that this option would have an effect similar to setting the heap manually via a rooted OS - i.e., it would raise the value of maxMemory()
while leaving getMemoryClass()
alone. There is another method, getLargeMemoryClass(), that indicates how much memory is allowable for an app using the largeHeap setting. The documentation for getLargeMemoryClass() states, "most applications should not need this amount of memory, and should instead stay with the getMemoryClass() limit."
我的期望(这似乎得到了上面的 largeHeap 数字的支持)是这个选项的效果类似于通过有根操作系统手动设置堆 - 即,它会提高 的值maxMemory()
而不getMemoryClass()
管它。还有另一种方法 getLargeMemoryClass(),它指示使用 largeHeap 设置的应用程序允许使用多少内存。getLargeMemoryClass() 的文档指出,“大多数应用程序不应该需要这个内存量,而应该保持 getMemoryClass() 限制。”
If I've guessed correctly, then using that option would have the same benefits (and perils) as would using the space made available by a user who has upped the heap via a rooted OS (i.e., if your app uses the additional memory, it probably will not play as nicely with whatever other apps the user is running at the same time).
如果我猜对了,那么使用该选项将具有与使用通过 root 操作系统增加堆的用户提供的可用空间相同的好处(和危险)(即,如果您的应用程序使用额外的内存,它可能不会与用户同时运行的任何其他应用程序一起很好地播放)。
Note that the memory class apparently need not be a multiple of 8MB.
请注意,内存类别显然不需要是 8MB 的倍数。
We can see from the above that the getMemoryClass()
result is unchanging for a given device/OS configuration, while the maxMemory() value changes when the heap is set differently by the user.
从上面我们可以看到,getMemoryClass()
对于给定的设备/操作系统配置,结果是不变的,而当用户设置不同的堆时,maxMemory() 值会发生变化。
My own practical experience is that on the G1 (which has a memory class of 16), if I manually select 24MB as the heap size, I can run without erroring even when my memory usage is allowed to drift up toward 20MB (presumably it could go as high as 24MB, although I haven't tried this). But other similarly large-ish apps may get flushed from memory as a result of my own app's pigginess. And, conversely, myapp may get flushed from memory if these other high-maintenance apps are brought to the foreground by the user.
我自己的实践经验是,在 G1(内存级别为 16)上,如果我手动选择 24MB 作为堆大小,即使我的内存使用量允许漂移到 20MB(大概它可以),我也可以运行而不会出错高达 24MB,虽然我还没有尝试过)。但是其他类似的大型应用程序可能会由于我自己的应用程序的贪婪而从内存中刷新。而且,相反,如果用户将这些其他高维护应用程序置于前台,我的应用程序可能会从内存中刷新。
So, you cannot go over the amount of memory specified by maxMemory()
. And, you should tryto stay within the limits specified by getMemoryClass()
. One way to do that, if all else fails, might be to limit functionality for such devices in a way that conserves memory.
因此,您不能超过maxMemory()
. 而且,您应该尽量保持在 指定的范围内getMemoryClass()
。如果所有其他方法都失败了,那么这样做的一种方法可能是以节省内存的方式限制此类设备的功能。
Finally, if you do plan to go over the number of megabytes specified in getMemoryClass()
, my advice would be to work long and hard on the saving and restoring of your app's state, so that the user's experience is virtually uninterrupted if an onStop()
/ onResume()
cycle occurs.
最后,如果您确实计划超过 中指定的兆字节数getMemoryClass()
,我的建议是长期努力地保存和恢复您的应用程序状态,以便在发生onStop()
/onResume()
循环时用户的体验几乎不会中断。
In my case, for reasons of performance I'm limiting my app to devices running 2.2 and above, and that means that almost all devices running my app will have a memoryClass of 24 or higher. So I can design to occupy up to 20MB of heap and feel pretty confident that my app will play nice with the other apps the user may be running at the same time.
就我而言,出于性能原因,我将我的应用程序限制为运行 2.2 及更高版本的设备,这意味着几乎所有运行我的应用程序的设备都将具有 24 或更高的 memoryClass。因此,我可以设计最多占用 20MB 的堆空间,并且非常有信心我的应用程序将与用户可能同时运行的其他应用程序完美配合。
But there will always be a few rooted users who have loaded a 2.2 or above version of Android onto an older device (e.g., a G1). When you encounter such a configuration, ideally, you ought to pare down your memory use, even if maxMemory()
is telling you that you can go much higher than the 16MB that getMemoryClass()
is telling you that you shouldbe targeting. And if you cannot reliably ensure that your app will live within that budget, then at least make sure that onStop()
/ onResume()
works seamlessly.
但是总会有一些 root 用户将 2.2 或更高版本的 Android 加载到旧设备(例如 G1)上。当您遇到这样的配置时,理想情况下,您应该减少内存使用量,即使maxMemory()
它告诉您可以使用比getMemoryClass()
告诉您应该定位的 16MB 高得多的内存。如果您不能可靠地确保您的应用程序在该预算范围内,那么至少要确保onStop()
/onResume()
无缝运行。
getMemoryClass()
, as indicated by Diane Hackborn (hackbod) above, is only available back to API level 5 (Android 2.0), and so, as she advises, you can assume that the physical hardware of any device running an earlier version of the OS is designed to optimally support apps occupying a heap space of no more than 16MB.
getMemoryClass()
,正如上面的 Diane Hackborn (hackbod) 所指出的,只能返回到 API 级别 5(Android 2.0),因此,正如她所建议的,您可以假设运行早期版本操作系统的任何设备的物理硬件都是设计的以最佳方式支持占用不超过 16MB 堆空间的应用程序。
By contrast, maxMemory()
, according to the documentation, is available all the way back to API level 1. maxMemory()
, on a pre-2.0 version, will probably return a 16MB value, but I dosee that in my (much later) CyanogenMod versions the user can select a heap value as low as 12MB, which would presumably result in a lower heap limit, and so I would suggest that you continue to test the maxMemory()
value, even for versions of the OS prior to 2.0. You might even have to refuse to run in the unlikely event that this value is set even lower than 16MB, if you need to have more than maxMemory()
indicates is allowed.
相比之下,maxMemory()
根据文档,可以一直返回到 API 级别 1。 maxMemory()
在 2.0 之前的版本中,可能会返回 16MB 的值,但我确实在我的(很久以后的)CyanogenMod 版本中看到用户可以选择低至 12MB 的堆值,这可能会导致较低的堆限制,因此我建议您继续测试该maxMemory()
值,即使对于 2.0 之前的操作系统版本也是如此。您甚至可能不得不拒绝运行,万一该值设置为甚至低于 16MB,如果您需要的数量超过maxMemory()
所允许的数量。
回答by hackbod
回答by Neil Traft
Debug.getNativeHeapSize()
will do the trick, I should think. It's been there since 1.0, though.
Debug.getNativeHeapSize()
会做的伎俩,我应该想。不过,它从 1.0 开始就存在了。
The Debug
class has lots of great methods for tracking allocations and other performance concerns. Also, if you need to detect a low-memory situation, check out Activity.onLowMemory()
.
这个Debug
类有很多很好的方法来跟踪分配和其他性能问题。此外,如果您需要检测内存不足的情况,请查看Activity.onLowMemory()
.
回答by android developer
Here's how you do it:
以下是您的操作方法:
Getting the max heap size that the app can use:
获取应用程序可以使用的最大堆大小:
Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();
Getting how much of the heap your app currently uses:
获取您的应用程序当前使用了多少堆:
long usedMemory=runtime.totalMemory() - runtime.freeMemory();
Getting how much of the heap your app can now use (available memory) :
获取您的应用程序现在可以使用多少堆(可用内存):
long availableMemory=maxMemory-usedMemory;
And, to format each of them nicely, you can use:
而且,要很好地格式化它们,您可以使用:
String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize);
回答by fhucho
This returns max heap size in bytes:
这将返回最大堆大小(以字节为单位):
Runtime.getRuntime().maxMemory()
I was using ActivityManager.getMemoryClass() but on CyanogenMod 7 (I didn't test it elsewhere) it returns wrong value if the user sets heap size manually.
我正在使用 ActivityManager.getMemoryClass() 但在 CyanogenMod 7 上(我没有在其他地方测试过),如果用户手动设置堆大小,它会返回错误的值。
回答by Zon
Some operations are quicker than java heap space manager. Delaying operationsfor some time can free memory space. You can use this method to escape heap size error:
有些操作比 java 堆空间管理器更快。延迟操作一段时间可以释放内存空间。您可以使用此方法来逃避堆大小错误:
waitForGarbageCollector(new Runnable() {
@Override
public void run() {
// Your operations.
}
});
/**
* Measure used memory and give garbage collector time to free up some
* space.
*
* @param callback Callback operations to be done when memory is free.
*/
public static void waitForGarbageCollector(final Runnable callback) {
Runtime runtime;
long maxMemory;
long usedMemory;
double availableMemoryPercentage = 1.0;
final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
final int DELAY_TIME = 5 * 1000;
runtime =
Runtime.getRuntime();
maxMemory =
runtime.maxMemory();
usedMemory =
runtime.totalMemory() -
runtime.freeMemory();
availableMemoryPercentage =
1 -
(double) usedMemory /
maxMemory;
if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {
try {
Thread.sleep(DELAY_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitForGarbageCollector(
callback);
} else {
// Memory resources are availavle, go to next operation:
callback.run();
}
}
回答by Tkraindesigns
Asus Nexus 7 (2013) 32Gig: getMemoryClass()=192 maxMemory()=201326592
华硕 Nexus 7 (2013) 32Gig:getMemoryClass()=192 maxMemory()=201326592
I made the mistake of prototyping my game on the Nexus 7, and then discovering it ran out of memory almost immediately on my wife's generic 4.04 tablet (memoryclass 48, maxmemory 50331648)
我犯了一个错误,在 Nexus 7 上对我的游戏进行原型设计,然后发现它在我妻子的通用 4.04 平板电脑上几乎立即耗尽内存(memoryclass 48,maxmemory 50331648)
I'll need to restructure my project to load fewer resources when I determine memoryclass is low.
Is there a way in Java to see the current heap size? (I can see it clearly in the logCat when debugging, but I'd like a way to see it in code to adapt, like if currentheap>(maxmemory/2) unload high quality bitmaps load low quality
当我确定 memoryclass 较低时,我需要重构我的项目以加载更少的资源。
Java 中有没有办法查看当前的堆大小?(调试时我可以在 logCat 中清楚地看到它,但我想要一种在代码中看到它的方法来适应,比如如果 currentheap>(maxmemory/2) unload high quality bitmaps load low quality
回答by qinqie
Runtime rt = Runtime.getRuntime();
rt.maxMemory()
value is b
值是 b
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()
value is MB
值为 MB
回答by Steve Haley
Do you mean programatically, or just while you're developing and debugging? If the latter, you can see that info from the DDMS perspective in Eclipse. When your emulator (possibly even physical phone that is plugged in) is running, it will list the active processes in a window on the left. You can select it and there's an option to track the heap allocations.
您是指以编程方式,还是只是在开发和调试时?如果是后者,您可以从 Eclipse 中的 DDMS 透视图查看该信息。当您的模拟器(甚至可能是插入的物理电话)运行时,它会在左侧的窗口中列出活动进程。您可以选择它,并且有一个选项可以跟踪堆分配。