不同 Android 设备上看似不一致的 OutOfMemory 崩溃
我正在制作一个必须在开始时加载所有位图的游戏,因为在内置的游戏编辑器中,用户可以将任何精灵放入关卡中。此外,关卡使用各种精灵,没有任何系统允许为每个关卡动态加载精灵组。
一段时间后,游戏中现在已经有 250 多个 png 图片,总大小为 3.5MB。
游戏使用 BitmapFactory.decodeStream 加载大多数精灵(大约 200 个),没有设置任何选项,并且还有大约 50 个其他精灵在活动的 xml 布局中引用。
当我在各种设备上进行测试时,游戏有时会耗尽内存,但我找不到模式,甚至决定我必须要多少,例如减少图像的大小或其数量。
我开发的手机 HTC 希望 Android 2.2 24MB VM 堆大小永远不会运行 OOM。
配备 Android 2.2 和 40MB VM 堆大小的 Dell Streak 也不会运行 OOM。
具有 Android 2.1 和 24MB VM 堆大小的 Motorola Milestone 成功加载了所有精灵,但在启动一项活动(开始菜单)时,被 ImageView 中使用的最后几幅图像阻塞。如果我注释掉一些这样的 ImageView,它会加载正常,但可能会在稍后的其他活动之一中卡住。它也不稳定,可能是因为碎片在不同的启动中发生的情况不同。
我朋友的 HTC Hero 2.2(不知道堆大小,是 16MB 吗?)也崩溃了。
最让人困惑的是,摩托罗拉有24MB,和HTC的愿望一样。 2.1 实现内存管理效率是否较低? (例如导致更多碎片?)或者所有摩托罗拉手机的内存管理都更差吗?那么为什么HTC Hero 2.2会崩溃呢?还有什么比 HTC Hero 更让 HTC 渴望的呢?
看起来 OOM 发生在旧手机上,但这是我迄今为止唯一发现的。
如果 OOM 仅发生在占市场份额 5% 的旧手机上,我可以通过收集崩溃报告并从支持列表中排除所有崩溃的设备,从受支持的设备中排除 2.1 或更具体的列表。否则我现在需要按某个常数因子(例如 1.6)缩小所有图像,这意味着调整所有 45 个级别的大小,这需要日复一日的设计和测试、重新定位 GUI 元素等。即使在那之后,我'仍然不确定在哪些设备上将位图总大小减少 2 倍足以避免 OOM。
对此有什么建议吗? 我应该为 BitmapFactory 设置任何特定选项吗?顺便说一句,大多数图像都有透明的背景像素,据我所知,不允许以 565 格式获取它们。
我花了两天时间浏览这里和其他地方,但仍然不知所措。
谢谢。
I am making a game which has to load all bitmaps at start because in the in-built game editor the user can put any of the sprites into the level. Also levels use various sprites without any system which would allow to load groups of sprites dynamically for each level.
After a while the are now already 250+ png images in the game with total size of 3.5MB.
The game loads most sprites (about 200) using BitmapFactory.decodeStream without any options set, and also there are about 50 other which are referenced in xml layouts of activities.
When I test on various devices, the game sometimes runs out of memory, but i can't find a pattern and even decide by HOW MUCH i have to, e.g. reduce the size of images or their number.
The phone on which i developed, HTC desire with Android 2.2 24MB VM heap size never runs OOM.
Dell Streak with Android 2.2 and 40MB VM heap size never runs OOM, too.
Motorola Milestone with Android 2.1 and 24MB VM heap size successfully loads all sprites but chokes on the few last images used in ImageView's when starting one of the activities (start menu). If I comment a few of such ImageViews out, it loads ok, but may choke on one of the other activities later. It's also not stable, probably because fragmentation happens differently in different launches.
HTC hero with 2.2 of my buddy (dunno the heap size, is it 16MB?) crashes as well.
What's most confusing is that Motorola has 24MB, the same as HTC desire. Is 2.1 implementing memory management less efficiently? (e.g. leads to more fragmentation?) Or is memory management worse by all Motorola phones? Then why does HTC hero with 2.2 crash? What's bigger in HTC desire than HTC hero?
Looks like OOM happens on older phones, but that's the only thing I've figured out so far.
If OOM only happens on older phones which are, say, 5% of the market, I can just exclude 2.1 or a more specific list from the supported devices by just gathering crash reports and excluding all that crashed from the list of supported. Otherwise I'd now need to scale down all my images by some constant factor (e.g. 1.6), which would mean resizing all the 45 levels which took days and days of designing and testing, repositioning GUI elements etc. Even after that, I'd still not be sure, on which devices the reduction of total size of bitmaps by a factor of e.g. 2 is enough to avoid OOMs.
Any advice on this?
Should I set any specific options for BitmapFactory? btw, most images have transparent bg pixels which, as far as i understand, doesn't allow getting them in 565 format.
I spent 2 days browsing here and in other places but am still at a loss.
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不得不处理你的问题的一个更简单的版本 - 我们有 3 个 2Mpix 层相互叠加,毫不奇怪,这有时会导致 OOM。
就我而言,我不是在彼此之上使用 3 个 ImageView,始终将所有 6 个 MPix 保留在内存中,而是手动混合图层,从而在任何时候最多在内存中保留 4 个 Mpix(并且在“时仅保留 2 个 MPix”)休息” - 我们的应用程序中的层发生了变化)。
这是一个经典的时空权衡——牺牲效率(时间)来获得内存(空间)。它有点慢,因为您必须在使用完每个位图后
recycle()
以确保释放内存。至于不一致的 OOM,可能与垃圾收集有关。您可以假设垃圾收集器是不确定的,因此任何内存压力也变得不确定(取决于 GC 最后启动的时间)。
简而言之,您必须非常非常小心地使用内存,而且没有办法绕过它。 *
* 理论上,您可以通过使用 NDK 并直接从操作系统分配来在 Dalvik 堆之外分配内存。这是一个巨大的黑客攻击,Dalvik 和你的分配器之间的桥梁将相当难看。
I've had to deal with a simpler version of your problem - we had 3 2Mpix layers on top of each other, which, unsurprisingly, sometimes caused OOM.
In my case, instead of using 3 ImageViews on top of each other, keeping all 6 MPix in memory at all times, I manually blended the layers, thus keeping at most 4 Mpix in memory at any one time (and only 2 MPix at "rest" - the layers changed in our application).
This is a classic time-space trade-off - sacrifice efficiency (time) to gain memory (space). It was somewhat slow because you had to
recycle()
each Bitmap after you were done with it to ensure the memory was freed.As for the inconsistent OOMs, it probably has to do with garbage collection. You can assume that the garbage collector is non-deterministic and thus any memory pressure becomes non-deterministic as well (depending on when the GC last kicked in).
The short summary is, you have to be very, very careful with your memory usage and there's no way around it. *
* In theory, you could allocate memory outside the Dalvik heap by using the NDK and allocating straight from the OS. It's a huge hack and the bridge between Dalvik and your allocator will be rather ugly.
首先,您需要找到到底是什么占用了您的所有内存。 看看这个。例如,也许您可以回收位图。
First you need to find what exactly is using all of your memory. Check this out. Maybe you could be recycling bitmaps, for instance.