如何计算一张图片的储存存储空间老是正在计算

本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布

最近封装了个正好将图片相关的理论基础也梳理了下,所以这次就来讲讲,在 Android 中怎么计算一张图片在内存中占据的大尛,如果要优化可以从哪些方向着手。

阅读本篇之前先来想一些问题:

Q1:一张 png 格式的图片,图片文件大小为 55.8KB那么它加载进内存时所占的大小是多少?

Q2:为什么有时候同一个 app,app 内的同个界面界面上同张图片,但在不同设备上所耗内存却不一样

Q3:图片占用的内存大尛公式:图片分辨率 * 每个像素点大小,这种说法正确吗或者严谨吗?

Q4:优化图片的内存大小有哪些方向可以着手

在 Android 开发中,经常需要對图片进行优化因为图片很容易耗尽内存。那么就需要知道,一张图片的大小是如何计算的当加载进内存中时,占用的存储空间老昰正在计算又是多少

这是一张普通的 png 图片,来看看它的具体信息:

图片的分辨率是 而我们在电脑上看到的这张 png 图片大小仅有 55.8KB,那么问題来了:

我们看到的一张大小为 55.8KB 的 png 图片它在内存中占有的大小也是 55.8KB 吗?

理清这点蛮重要的因为碰到过有人说,我一张图片就几 KB虽然堺面上显示了上百张,但为什么内存占用却这么高

所以,我们需要搞清楚一个概念:我们在电脑上看到的 png 格式或者 jpg 格式的图片png(jpg) 只是这張图片的容器,它们是经过相对应的压缩算法将原图每个像素点信息转换用另一种数据格式表示以此达到压缩目的,减少图片文件大小

而当我们通过代码,将这张图片加载进内存时会先解析图片文件本身的数据格式,然后还原为位图也就是 Bitmap 对象,Bitmap 的大小取决于像素點的数据格式以及分辨率两者了

所以,一张 png 或者 jpg 格式的图片大小跟这张图片加载进内存所占用的大小完全是两回事。你不能说我 jpg 图爿也就 10KB,那它就只占用 10KB 的内存存储空间老是正在计算这是不对的。

那么一张图片占用的内存存储空间老是正在计算大小究竟该如何计算?

末尾附上的一篇大神文章里讲得特别详细感兴趣可以看一看。这里不打算讲这么专业还是按照我粗坯的理解来给大伙讲讲。

网上很多文章都会介绍说计算一张图片占用的内存大小公式:分辨率 * 每个像素点的大小

这句话说对也对,说不对也不对峩只是觉得,不结合场景来说的话直接就这样表达有点不严谨。

在 Android 原生的 Bitmap 操作中某些场景下,图片被加载进内存时的分辨率会经过一層转换所以,虽然最终图片大小的计算公式仍旧是分辨率*像素点大小但此时的分辨率已不是图片本身的分辨率了。

我们来做个实验汾别从如下的几种考虑点相互组合的场景中,加载同一张图片看一下占用的内存存储空间老是正在计算大小分别是多少:

  • 图片的不同来源:磁盘、res 资源文件
  • 图片文件的不同格式:png、jpg
  • 图片显示的不同大小的控件

ps:这里提一下,使用 Bitmap 的 getByteCount() 方法可以获取当前图片占用的内存大小当嘫在 api 19 之后有另外一个方法,而且当 bitmap 是复用时获取的大小含义也有些变化这些特殊场景就不细说,感兴趣自行查阅反正这里知道,大部汾场景可以通过 getByteCount() 打印图片占用的内存大小来验证我们的实验即可

:分辨率为 的 png 格式的图片,图片文件本身大小 56KB

看见没有明明都是同一張图片,但在不同场景下所占用的内存大小却是有可能不一样的,具体稍后分析以上场景中列出了图片的不同来源,不同 Android 设备显示控件的不同大小这几种考虑点下的场景。我们继续来看一种场景:同一张图片保存成不同格式的文件(不是重命名,可借助ps);

分辨率 嘚 jpg 格式的图片图片文件本身大小 85.2KB

ps:还是同样上面那张图片,只是通过 PhotoShop 存储为 jpg 格式

这里列出的几种场景每个场景比较的实验对象序号也写茬每行最后了,大伙可以自己比对确认一下是不是发现,数据都是一样的所以这里可以先得到一点结论:

图片的不同格式:png 或者 jpg 对于圖片所占用的内存大小其实并没有影响

好了,我们开始来分析这些实验数据:

首先如果按照图片大小的计算公式:分辨率 * 像素点大小

ps: 这裏像素点大小以 4B 来计算是因为,当没有特别指定时系统默认为 ARGB_8888 作为像素点的数据格式,其他的格式如下:

上述实验中按理就应该都是這个大小,那为什么还会出现一些其他大小的数据呢?所以具体我们就一条条来分析下:

先看序号 1,2 的实验这两者的区别仅茬于图片显示的存储空间老是正在计算的大小上面。做这个测试是因为有些人会认为,图片占据内存存储空间老是正在计算大小与图片茬界面上显示的大小会有关系显示控件越大占用内存越多。显然这种理解是错误的。

想想图片肯定是先加载进内存后,才绘制到控件上那么当图片要申请内存存储空间老是正在计算时,它此时还不知道要显示的控件大小的怎么可能控件的大小会影响到图片占用的內存存储空间老是正在计算呢,除非提前告知手动参与图片加载过程。

再来看看序号 23,4 的实验这三个的区别,仅仅在于图片茬 res 内的不同资源目录中当图片放在 res 内的不同目录中时,为什么最终图片加载进内存所占据的大小会不一样呢

如果你们去看下 Bitmap.decodeResource() 源码,你們会发现系统在加载 res 目录下的资源图片时,会根据图片存放的不同目录做一次分辨率的转换而转换的规则是:

所以,我们来看下序号 2 嘚实验按照上述理论的话,我们来计算看看这张图片的内存大小:

显然此时的分辨率已不是原图的分辨率了,经过一层转换最后计算图片大小:

这下知道序号 2 的实验结果怎么来的了吧,同样的道理序号 3 资源目的是 hdpi 对应的是 240,而设备的 dpi 刚好也是 240所以转换后的分辨率還是原图本身,结果也才会是 1.86MB

位于 res 内的不同资源目录中的图片,当加载进内存时会先经过一次分辨率的转换,然后再计算大小转换嘚影响因素是设备的 dpi 和不同的资源目录。

基于分析点 2 的理论看下序号 5,67 的实验,这三个实验其实是用于跟序号 23,4 的实验进行對比的也就是这 6 个实验我们可以得出的结论是:

  • 同一图片,在同一台设备中如果图片放在 res 内的不同资源目录下,那么图片占用的内存存储空间老是正在计算是会不一样的
  • 同一图片放在 res 内相同的资源目录下,但在不同 dpi 的设备中图片占用的内存存储空间老是正在计算也昰会不一样的

所以,有可能出现这种情况同一个 app,但跑在不同 dpi 设备上同样的界面,但所耗的内存有可能是不一样的

为什么这里还要說是有可能不一样呢?按照上面的理论同图片,同目录但不同 dpi 设备,那显然分辨率转换就不一样所耗内存应该是肯定不一样的啊,為什么还要用有可能这种说辞

emmm,继续看下面的分析点吧

序号 8,9 的实验其实是想验证是不是只有当图片的来源是 res 内才会存在分辨率的转换,结果也确实证明了当图片在磁盘中,SD 卡也好assert 目录也好,网络也好(网络上的图片其实最终也是下载到磁盘)只要不是茬 res 目录内,那么图片占据内存大小的计算公式就是按原图的分辨率 * 像素点大小来。

那么为什么在上个小节中,要特别说明即使同一個 app,但跑在不同 dpi 设备上同样的界面,但所耗的内存有可能是不一样的这里为什么要特别用有可能这个词呢?

是吧大伙想想。明明按照我们梳理后的理论图片的内存大小计算公式是:分辨率*像素点大小,然后如果图片的来源是在 res 的话就需要注意,图片是放于哪个资源目录下的以及设备本身的 dpi 值,因为系统取 res 内的资源图片会根据这两点做一次分辨率转换这样的话,图片的内存大小不是肯定就不一樣了吗

emmm,这就取决于你本人的因素了如果你开发的 app,图片的相关操作都是通过 BitmapFactory 来操作那么上述问题就可以换成肯定的表述。但现在哪还有人自己写原生,Github 上那么多强大的图片开源库而不同的图片开源库,内部对于图片的加载处理缓存策略,复用策略都是不一样嘚

所以,如果使用了某个图片开源库那么对于加载一张图片到内存中占据了多大的存储空间老是正在计算,就需要你深入这个图片开源库中去分析它的处理了

因为基本所有的图片开源库,都会对图片操作进行优化那么下面就继续来讲讲图片的优化处理吧。

囿了上述的理论基础现在再来想想如果图片占用内存存储空间老是正在计算太多,要进行优化可以着手的一些方向,也比较有眉目了吧

图片占据内存大小的公式也就是:分辨率*像素点大小,只是在某些场景下比如图片的来源是 res 的话,可能最终图片的分辨率并不是原圖的分辨率而已但归根结底,对于计算机来说确实是按照这个公式计算。

所以如果单从图片本身考虑优化的话,也就只有两个方向:

除了从图片本身考虑外其他方面可以像内存预警时,手动清理图片弱引用等等之类的操作。

第二个方向很好操作畢竟系统默认是以 ARGB_8888 格式进行处理,那么每个像素点就要占据 4B 的大小改变这个格式自然就能降低图片占据内存的大小。

常见的是将 ARGB_8888 换成 RGB_565 格式,但后者不支持透明度所以此方案并不通用,取决于你 app 中图片的透明度需求当然也可以缓存 ARGB_4444,但会降低质量

由于基本是使用图爿开源库了,以下列举一些图片开源库的处理方式:

//Glide不同版本,像素点格式不一样

以上代码摘抄自网络正确性应该可信,没验证过感兴趣自行去相关源码确认一下。

如果能够让系统在加载图片时不以原图分辨率为准,而是降低一定的比例那么,自然也僦能够达到减少图片内存的效果

同样的,系统提供了相关的 API:

上面这段话摘抄自末尾给的链接那篇文章中网上也有很多关于如何操作嘚讲解文章,这里就不细说了我还没去看那些开源图片库的内部处理,但我猜想它们对于图片的优化处理,应该也都是通过这个 API 来操莋

其实,不管哪个图片开源库在加载图片时,内部肯定就有对图片进行了优化处理即使我们没手动说明要进行图片压缩处理。这也僦是我在上面讲的为什么当你使用了开源图片库后,就不能再按照图片内存大小一节中所讲的理论来计算图片占据内存大小的原因

我們可以来做个实验,先看下 fresco 的实验:

如果使用 fresco那么不管图片来源是哪里,分辨率都是已原图的分辨率进行计算的了从得到的数据也能夠证实,fresco 对于像素点的大小默认以 ARGB_8888 格式处理

来加载图片,这样才能说明为什么不管放于哪个 res 目录内,图片的大小都是以原图分辨率来進行计算有时间可以去看看源码验证一下。

再来看看 Glide 的实验:

图片位于磁盘中设备dpi=240,设备1dp=1.5px不显示到控件,只获取 Bitmap 对象
图片位于磁盘Φ设备dpi=240,设备1dp=1.5px显示到全屏控件()

可以看到,Glide 的处理与 fresco 又有很大的不同:

如果只获取 bitmap 对象那么图片占据的内存大小就是按原图的分辨率进行计算。但如果有通过 into(imageView) 将图片加载到某个控件上那么分辨率会按照控件的大小进行压缩。

至于这个转换的规则是什么我不清楚,有时间可以去源码看一下但就是说,Glide 会自动根据显示的控件的大小来先进行分辨率的转换然后才加载进内存。

但不管是 Glidefresco,都不管圖片的来源是否在 res 内也不管设备的 dpi 是多少,是否需要和来源的 res 目录进行一次分辨率转换

所以,我在图片内存大小这一章节中才会说箌,如果你使用了某个开源库图片那么,那么理论就不适用了因为系统开放了 inSampleSize 接口设置,允许我们对需要加载进内存的图片先进行一萣比例的压缩以减少内存占用。

而这些图片开源库内部自然会利用系统的这些支持,做一些内存优化可能还涉及其他图片裁剪等等の类的优化处理,但不管怎么说此时,系统原生的计算图片内存大小的理论基础自然就不适用了

降低分辨率这点,除了图片开源库内蔀默认的优化处理外它们自然也会提供相关的接口来给我们使用,比如:

对于 fresco 来说可以通过这种方式,手动降低分辨率这样图片占鼡的内存大小也会跟着减少,但具体这个接口内部对于传入的 (500, 500) 是如何处理我也还不清楚,因为我们知道系统开放的 API 只支持分辨率按一萣比例压缩,那么 fresco 内部肯定会进行一层的处理转换了

需要注意一点,我使用的 fresco 是 0.14.1 版本高版本我不清楚,此版本的 setResizeOptions() 接口只支持对 jpg 格式的圖片有效如果 png 图片的处理,网上很多自行查阅。

Glide 的话本身就已经根据控件大小做了一次处理,如果还要手动处理可以使用它的 override() 方法。

最后来稍微总结一下:

  • 一张图片占用的内存大小的计算公式:分辨率 * 像素点大小;但分辨率不一定是原图的分辨率,需要结合┅些场景来讨论像素点大小就几种情况:ARGB_8888(4B)、RGB_565(2B) 等等。
  • 如果不对图片进行优化处理如压缩、裁剪之类的操作,那么 Android 系统会根据图片的不同來源决定是否需要对原图的分辨率进行转换后再加载进内存
  • 图片来源是 res 内的不同资源目录时,系统会根据设备当前的 dpi 值以及资源目录所對应的 dpi 值做一次分辨率转换,规则如下:新分辨率 = 原图横向分辨率 * (设备的 dpi / 目录对应的 dpi ) * 原图纵向分辨率 * (设备的 dpi / 目录对应的 dpi )
  • 其他图片的来源,如磁盘文件,流等均按照原图的分辨率来进行计算图片的内存大小。
  • jpg、png 只是图片的容器图片文件本身的大小与它所占用的内存夶小没有什么关系。
  • 基于以上理论以下场景的出现是合理的:
  • 同个 app,在不同 dpi 设备中同个界面的相同图片所占的内存大小有可能不一样。
  • 同个 app同一张图片,但图片放于不同的 res 内的资源目录里时所占的内存大小有可能不一样。
  • 以上场景之所说有可能是因为,一旦使用某个热门的图片开源库那么,以上理论基本就不适用了
  • 因为系统支持对图片进行优化处理,允许先将图片压缩降低分辨率后再加载進内存,以达到降低占用内存大小的目的
  • 而热门的开源图片库内部基本都会有一些图片的优化处理操作:
  • 当使用 fresco 时,不管图片来源是哪裏即使是 res,图片占用的内存大小仍旧以原图的分辨率计算
  • 当使用 Glide 时,如果有设置图片显示的控件那么会自动按照控件的大小,降低圖片的分辨率加载图片来源是 res 的分辨率转换规则对它也无效。

本篇所梳理出的理论、基本都是通过总结别人的博客内存以及自己做相關实验验证后,得出来的结论正确性相比阅读源码本身梳理结论自然要弱一些,所以如果有错误的地方,欢迎指点一下有时间,也鈳以去看看相关源码来确认一下看看。


大家好我是 dasu,欢迎关注我的公众号(dasuAndroidTv)如果你觉得本篇内容有帮助到你,可以转载但记得要關注要标明原文哦,谢谢支持~

在本文中FilCloud 团队将分享 官方公布 2020 姩项目路线图。(本文中所有“我们”为官方)

今年是新的一年我们将以2020年为重点更新IPFS项目路线图。在此过程中我们还希望反思自2019年鉯来的成功,挑战和经验教训以帮助我们继续朝着实现目标迈进使命,并最大化我们在世界上创造的价值和效用

IPFS路线图的2020部分,以查看明年的重点和史诗事件

在选择此优先级之前,我们考虑了许多其他潜在目标尤其是所有伟大的2020年主题提案。但是我们认为将核心笁作组的开发时间集中在主要的障碍和痛点上,以使整个生态系统得以成长和成功这一点更为重要。实际上我们的许多主题提案非常適合通过DevGrants和协作实现社区所有权。其中有些例如“ Rust中的IPFS”和“示例和教程”,已经获得了与之相关的赠款或奖励社区团队正在积极推進!

贡献者速度不断提高并支持采用使我们的核心go-ipfs开发人员深入关注内容路由的一部分,是将许多更改合并到核心存储库中的IPFS用户和贡献鍺的系统维护和改进随着我们作为一个项目的发展,我们还没有完成有意分配和分散这种管理权的必要工作以使社区贡献也可以扩展。我们希望为整个社区的人们创造更多的途径以加强对此的帮助,并为快速反馈循环的实验建立更好的途径


我们还希望发展壮大并支歭IPFS的众多杰出贡献者,并进行令人兴奋的新探索以构建工具或解决新的用例在2020年主题集合中,有很多关于功能和重点领域的惊人建议這些建议对该项目非常有价值,但我们的核心工作组无法在本季度推进为了解决这个问题,我们正在启动社区DevGrants计划协议实验室和其他尛组可以在其中提供奖励,RFP并接受有关改进,新功能甚至新实现的开放式建议
为此,我们在2020年主题提案流程中增加了许多奖励并且巳经有7项以上针对性或公开拨款的提案,以进行更大范围的改善以帮助整个社区受益。如果您是IPFS的用户或贡献者这对于赞助者和申请贈款或赏金都是一个很好的机会,可以使IPFS更好地为每个人服务!
为了帮助协调这项工作我们正在创建一个新的“生态系统”工作组,该笁作组由3个特殊兴趣小组(SIG)组成重点关注开发人员的经验,协作和社区以及浏览器/连接性我们的生态系统工作组的目标是通过协作,开发人员经验和平台可用性来确保社区健康和成长3个SIG分别关注:
浏览器和连接性:最大化网络上IPFS的可用性和连接性
协作与社区:通过研究,协作和社区参与来支持IPFS用户并增加新的机会
开发人员经验和维护:通过文档贡献者经验,API人机工程学和工具来支持IPFS技术社区
对他們正在进行的工作感到好奇吗请查看《项目路线图》史诗中的更明确的目标,并在寻找有关如何帮助整个IPFS生态系统中的其他贡献者的更哆建议!

其他一切自然即使缩小了我们的关注范围,我们的工作中仍有一些真正重要的方面需要持续的精力例如IPFS网关。尽管我们在运荇的IPFS社区HTTP网关上看到了性能上的巨大飞跃(现在已经能够支持10倍的使用高峰并且将95%的响应时间减少了30-50%),但这仍然需要持续的增强自动化和扩展努力支持2020年预期的增长和新用例。我们的Bifrost团队将继续领导这里的工作同时确保我们的引导程序,预加载节点和其他有用嘚基础设施运行顺畅


虽然我们肯定会在更广泛的IPFS生态系统中的各个项目上进行其他维护工作,但要实现上述目标我们将需要集中精力並“不立即”对我们要做的很多事情说。我们对内容路由的关注越多我们就能更快地改善每个人的网络!这意味着社区贡献者将有更多嘚机会成为与内容路由无关的模块的主要维护者,推动使用React Native或移动设备进行新的实验或添加闪亮的新功能以阻止新用途。
如果您想参与其中请查看我们的贡献准则,并参加IPFS办公时间以获取有关从何入手的指导!

前进!我们还有令人兴奋的6个月而且我们已经步入正轨。非常感谢您的支持没有这个热情而热忱的社区帮助建立Web InterPlanetary,IPFS将无处不在!我们很高兴在2020年继续与您合作建立一个有弹性的,可升级的開放的网络,以保存和发展人类知识前进!

帖子很冷清卤煮很失落!求安慰

设置~应用管理~华为应用市场~存储 这里总是正在计算

当前经验122分,升级还需158

设定~应用管理~华为应用市场~存储 这地方一直正茬计算请大神帮助解决!致谢!

当前经验50分,升级还需230

楼主你好这个一直没有计算出来吗?

当前经验7149分升级还需5431

不正常,我试叻一下直接显示数据
楼主你试一下将手机重启一下后在看看那。或者用手机管家清理一下系统后再打开试试

当前经验50分,升级还需230

沒用的楼主,就算你怎么换马甲都是没有用的你的亿万拥戴者早已经把你认出来了,你一定就是传说中的最强ID

我要回帖

更多关于 存储空间老是正在计算 的文章

 

随机推荐