Android中的位图

Sam*_*muh 29 android bitmap

我有一些关于Bitmap对象和内存及其一般分类的问题.

  1. 什么是内存或本机位图?
  2. Bitmap内存与堆内存有何不同?

Tre*_*hns 33

支持Bitmap对象的内存是使用本机代码(malloc())而不是Java new关键字分配的.这意味着内存由操作系统直接管理,而不是由Dalvik管理.

本机堆和Dalvik堆之间唯一真正的区别是Dalvik的堆是垃圾收集的,本地堆不是.

尽管如此,这里并没有多大区别.当你的Bitmap对象被垃圾收集时,它的析构函数将回收本机堆中的相关内存.

资源:

  • 为了清楚起见,上面的答案适用于Android 2.x及以下版本.从Android 3开始,位图实例再次反堆.这很容易检查:在android 2.x中创建一个位图将使Java堆大小非常小,在Adnroid 3.x中创建它将为Java堆添加大量字节. (5认同)

hac*_*bod 32

这里有一个重要的微妙之处:虽然Bitmap像素是在本机堆中分配的,但Dalvik中的一些特殊技巧会使它与Java堆相对应.这样做有两个原因:

(1)控制应用程序分配的内存量.如果没有计费,应用程序可以分配大量内存(因为Bitmap对象本身非常小但可以保留任意大量的本机内存),超出了16MB或24MB堆限制.

(2)帮助确定何时进行GC.如果没有会计,您可以在100个Bitmap对象上分配和释放引用; GC不会运行,因为这些对象很小,但它们实际上可能代表了大量的兆字节实际分配,现在没有及时进行GC.通过将这些分配计入Java堆,垃圾收集器将在它认为使用内存时运行.

请注意,在许多方面,这是一个实现细节; 它很可能在未来发生变化,尽管这种基本行为将保持某种形式,因为这些都是管理位图分配的重要特征.

  • 第一条评论是错误的,所有电话都计算针对Dalvik堆限制的位图分配.需要注意的主要变化是,从Android 3.0开始,分配实际上是在Dalvik堆中完成的,因此您不再需要处理GC不能像它应该那样积极运行的情况. (10认同)
  • 你是对的.在处理回收的位图时,GC仍处于延迟状态.我发现不可预知的行为,除非我在回收位图后手动运行GC(包括下一个"加载"返回再循环位图的副本而不是实际从磁盘加载它的倾向) (2认同)

Dav*_*son 12

从野外部署,我发现了以下设备:

  • 限制为16 MiB的Java堆的设备(位图几乎无限制).
  • 限制为16 MiB的设备(java堆+本机位图存储)
  • 限制为24 MiB的Java堆的设备(位图几乎无限制).
  • 限制为24 MiB的设备(java堆+本机位图存储)

24 MiB往往是高分辨率设备,可以使用Runtime.getRuntime().maxMemory()检测.现在还有32MiB设备,默认情况下,一些有根电话的设备有64MiB.以前,我曾经多次试图弄清楚发生了什么事情.我认为所有设备都将位图计入堆限制.但要对机器人舰队进行任何全面的概括是非常困难的.

这在Android上是一个非常讨厌的问题,而且非常令人困惑.这个限制和它的行为记录很少,很复杂,而且非常不直观.它们也因设备和操作系统版本而异,并且有几个已知的错误.部分问题是限制不准确 - 由于堆碎片,你将在实际限制之前很好地击中OOM,并且必须保守地留下一两或两个缓冲区.更糟糕的是,我有几个设备存在本地段错误(100%是Android本身的错误),在你获得java OOM异常之前就已经发生了,因为你甚至无法捕获它,因此永远不会达到极限是非常重要的本机崩溃.有关我的调查的更多详细信息,请查看此帖子.在同一篇文章中,我将解释如何根据限制来衡量使用情况并避免崩溃.

java堆的大小是Runtime.getRuntime().totalMemory().

没有简单的方法来测量本机位图存储的大小.可以使用Debug.getNativeHeapAllocatedSize()来测量整个本机堆,但只有位图计数到极限(我认为).

  • @Carl - 我拿了一本字典,其中180k字平均长度为10个字符(15M存储为Java字符串),并将其塞进400k.:)问题是,由于任何专有存储格式都与本机渲染代码不兼容,因此减少位图内存确实非常困难.在具有半个物理内存的设备上,使内存人为地昂贵似乎非常愚蠢.并且本机代码可以分配1 + G而不会受到操作系统的投诉.这只是惩罚Java开发人员的一种方式. (5认同)