在模拟器下加载体积较大的图片时可能会导致内存溢出,在 LogCat 中会看到 java.lang.OutOfMemoryError: bitmap size exceeds VM budget 的报错,但是同样的程序在真机上运行时候却不会发下因为内存溢出导致程序的崩溃。这是因为 Android 系统的手机在系统底层指定了堆内存的上限值,大部分手机的缺省值是 16MB,不过也有些高配置的机型是 24MB 的,所以我们的程序在申请内存空间时,为了确保能够成功申请到内存空间,应该保证当前已分配的内存加上当前需要分配的内存值的总大小不能超过当前堆的最大内存值,而且内存管理上将外部内存完全当成了当前堆的一部分,也就是说 Bitmap 对象通过栈上的引用来指向堆上的 Bitmap 对象,而堆上的 Bitmap 对象又对应了一个使用了外部存储的 native 图像,也就是实际上使用的字节数组 byte[] 来存储的位图信息,因此解码之后的 Bitmap 的总大小就不能超过 8M了。补充说明:堆(HEAP)是 VM 中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,当堆内存实际的利用率偏离设定的值的时候,虚拟机会在 GC 的时候调整堆内存大小,让实际占用率向个百分比靠拢。比如初始的 HEAP 是 4M 大小,当 4M 的空间被占用超过 75% 的时候,重新分配堆为 8M 大;当 8M 被占用超过75% 分配堆为16M 大。倒过来,当 16M 的堆利用不足 30% 的时候,缩减它的大小为 8M 大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。
目前我们关心的是:如果想继续在模拟器上运行会导致内存溢出的程序,这时我们就需要增加模拟器上堆内存的大小,来保证有足够的空间满足当前程序中图片资源对内存的申请。在模拟器的 Hardware 设置项中,有一项 Max VM application heap size 可以用来调整模拟器的堆内存上限大小,我们只需要增大该值直到能满足程序正常运行为止即可。