任何人都可以解释下面的Logcat消息:
D/dalvikvm(4440): GC_EXTERNAL_ALLOC freed 338K, 47% free 6427K/11911K, external 20418K/22446K, paused 53ms
E/dalvikvm-heap(4440): 2519424-byte external allocation too large for this process.
D/dalvikvm(4440): GC_FOR_MALLOC freed <1K, 47% free 6427K/11911K, external 20398K/22446K, paused 40ms
E/GraphicsJNI(4440): VM won't let us allocate 2519424 bytes
答案 0 :(得分:3)
在早期版本的Android中,某些本机框架代码会告诉VM本机分配。这种“外部分配”机制是一个丑陋的黑客,因此原生分配会导致Dalvik VM进行垃圾收集传递。
基本问题是Java语言Bitmap对象使用本机内存进行像素存储。由于托管堆对象很小,并且本机堆对象很大,因此您可以分配大量的位图而不会导致GC。这导致应用程序膨胀,系统变慢。
因此,引入了“外部分配”。只要在本机堆上分配了Bitmap的像素存储,就会从托管堆中减去相同数量的内存。我们的想法是,如果您的堆填充了不再引用的位图,您将耗尽托管堆空间并且GC将会触发。
(不幸的是,GC实际上无法释放本机存储 - 您需要运行终结器来执行此操作,并且在GC完成后终结器在单独的传递中运行。有一段时间,本机对象也持有一些额外的托管堆对象,所以你必须GC + finalize + GC来实际清理所有东西。)
关于外部分配的我最喜欢的部分是API是一个简单的“增加N”/“减少N”,这意味着没有办法将本机堆与托管堆对象相关联,或者检查泄漏。因为有关Bitmap的所有信息都保存在本机对象中,所以您甚至无法猜测需要多少本机存储,因此无法查看hprof转储并计算出Bitmap实际使用了多少内存
在Android 3.0(“Honeycomb”)中,像素存储被移动到托管堆上,并删除了外部分配机制。
因此,您的问题中的日志消息意味着:某些代码(可能是Bitmap)想要分配2.5MB的本机堆,但这会超出VM的外部分配堆限制。你需要弄清楚是什么占用了20MB的外部分配存储空间并释放了一些存储空间。
获取外部分配信息的唯一方法是观察事件日志。几年前我把一个剧本放在一起(gclog.py - 在AOSP dalvik / tools中待了一段时间)。我不知道它是否还会做任何有用的事情。我在this old thread讨论如何使用它。