热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

android内存分析bitmap,AndroidBitmap的内存大小是如何计算的?

一、前言本来只想说下Bitmap和内存的基本关系,但发现如果真的想把这看似简单的事情说清楚,实际上未必那么简单,你不信?不妨

一、前言

本来只想说下Bitmap和内存的基本关系,但发现如果真的想把这看似简单的事情说清楚,实际上未必那么简单,你不信?不妨先尝试下回答下面几个问题!

问1:什么是dpi?什么是dp?答:你在侮辱我?我拒绝回答!(:无辜脸

问2:以Nexus6为例,分辨率1440*2560,5.96英寸,ppi是什么?dpi是什么?1dp是多少像素?

问3:还以Nexus6为例,一张180*180的图片,放置在设置了wrap_content属性的ImageView中,当这张图片,分别放在drawable-nodpi,drawable-mdpi,drawable-hdpi, drawable-xxhdpi,drawable-xxxhdpi这几个资源目录中,在屏幕上分别显示多大(像素)的图片?

问4:这张图片占用的内存大小分别为多少?

问5:如果设置ImageView的宽和高为固定的值,如50px,那么上述情况下,加载的Bitmap占用内存大小分别为多大?

本文主要围绕上述问题,介绍Android图片资源加载的基本机制,图片的内存大小如何计算,以及内存图片分析工具。

二、基础概念px:像素(pixel),指的是屏幕上的物理点,最小的独立显示单位

ppi:每英寸像素点(Pixels Per Inch),之前我自己的理解就是使用勾股定理,通过屏幕长宽计算出对角线的长度,再除以屏幕对角线英寸值。

dpi:每英寸点(Dots Per Inch),和ppi有什么区别?

dp:像素无关点(Density-Independent pixel),这个Android定义的虚拟值,和px关系式是px = dp * (dpi / 160),为啥?

ppi

ppi指的是水平方向或者竖直方向上每英寸的像素值,先说为啥很多对ppi的理解都有问题。很多文章利用勾股定理计算手机屏幕对角线像素个数!!但是手机屏幕的像素分布是点阵分布,点阵的对角线像素点不是用勾股定理算出来的,而是等于它的行数或者列数,为啥用对角线计算?因为一般手机的尺寸说的就是对角线英寸值,而不知道长宽的英寸值。这里有个公式推导:

设 X/x = Y/y = ppi,这里X为水平像素值,x为水平英寸值,Y为竖直像素值,y为竖直英寸值。则(X²+Y²)/(x²+y²)=(X/x)²=(Y/y)²,这个公式可通过勾股定理和相似三角形原理证明。ppi的计算只是形式和勾股定理一样但并不是勾股定理的意思,分子也不是对角线的像素数!!ppi的计算公式可表示为:√(X²+Y²)/对角线英寸。但不意味着ppi是使用勾股定理计算对角线像素值获得的~~

42c0e00d01aac67ba4d1b1729eae35b4.png

dpi

dpi是由ppi确定的,还是以Nexue6为例,通过ppi的计算公式,可以计算出Nexues6的ppi为492,参照下表,应该在xxxhdpi的范围内,但它的dpi并不是492。实际上dpi只有120(low)、160(medium)、240(high)、260、280、300、320(xhigh)、340、360、400、420、480(xxhpdi)、560、640(xxxhpi)这几种,可以参照android.util.DisplayMetrics的源码。通过getResources().getDisplayMetrics().densityDpi可以获取手机实际的dpi。

e46f7b3b93079ff3b0dd7aad22168621.png

dp

1dp在Nexues6上是多少像素?

1dp * (560/160) = 3.5px

如何更改手机的dpi

需要root的手机

更改/system/build.prop中的ro.sf.lcd_density属性,这个值越小,屏幕密度越高

adb reboot 重启手机

如何快速查看手机屏幕信息

adb shell dumpsys display | findstr DisplayDeviceInfo

三、回到问题

以Nexus6为例,一张180*180的图片,放在设置了wrap_content属性的ImageView中,当这张图片,分别放置在drawable-nodpi,drawable-mdpi,drawable-hdpi, drawable-xxhdpi,drawable-xxxhdpi这几个资源目录中,在屏幕上分别显示多大(像素)的图片?

答:根据上面的分析,可以看到nexus6,是属于xxxhpi的屏幕,获取到dpi为560。如果把180大小的图片只放在xxxhdpi目录中,是不是屏幕就会显示180px的大小?其实并不是,dpi=640的才是真正的xxxhdpi(这里需要看DisplayMetrics的源码),当Android系统加载图片时,会针对当前系统的dpi和图片目录的source dpi比较做相应比例的缩放,如果一张图片放在drawable-xxxhdpi目录,这是告诉系统,针对dpi为640的手机屏幕上,这张图片是刚刚好的,它的scale为1.0,同理,drawable-xxhpi对应480dpi,drawable-xhdpi对应的是320dpi。如果希望180*180在nexues6的屏幕上按照原有尺寸显示,只有将其放在drawable-nodpi或者drawable-560dpi目录中才可以。

回到问题,如果将180*180放入hdpi目录中,那实际显示的图片大小应该为:int (180 * (560 / 240) +0.5f ) = 420px,实际图片的大小应该为420px!同理:

放入xhdpi目录中,实际大小应该为int (180 * (560 / 320) +0.5f ) = 315px

放入xxhdpi目录中,实际大小应该为int (180 * (560 / 480) +0.5f ) = 210px

如果用小的Bitmap容器,放置较大的Bitmap,那这个Bitmap的尺寸大小是按照容器的大小计算?还是按照dpi缩放的规则计算?

四、一张图片占多大内存

现在我们已经知道了一张图片放置在不同的资源目录中,系统decode的bitmap的尺寸大小是如何计算的了。一张图片大概占用多少内存,其实只用看一个像素占用多少内存就可以喽?我们都知道屏幕上的颜色是有R,G,B加透明度表示的,Android官方支持的RGB格式,主要是ALPHA_8,RGB_565,ARGB_4444,ARGB_8888这几种。

以ARGB_8888为例,表示一个像素点,使用8位表示透明度,8位表示Red,8位表示Green,8位表示Blue。加起来,一个像素就需要4byte,同理,RGB_565一个像素需要2byte。

1

2

3

4

5

6

7

8

9

10

11public enum Config {

ALPHA_8 (1),

RGB_565 (3),

@Deprecated

ARGB_4444 (4),

ARGB_8888 (5);

final int nativeInt;

Config(int ni) {

this.nativeInt = ni;

}

}

Android decode资源图片时默认会选择ARGB_8888,如果将180*180放入hdpi目录中,那实际大小应该为int (180 * (560 / 240) +0.5f ) = 420px,像素内存大小为 420 * 420 * 4 = 705600byte = 689kb。同理:

放入xhdpi目录中,实际大小应该为int (180 * (560 / 320) +0.5f ) = 315px,像素内存大小为315 * 315 * 4 = 396900byte = 387.6kb

放入xxhdpi目录中,实际大小应该为int (180 * (560 / 480) +0.5f ) = 210px,像素内存大小为210 * 210 * 4 = 176400byte = 172.2kb

五、如何分析内存中的图片问题?

说了这么多,终于到了我原本想说的。Android的内存优化需要重点关注的几个方面,Bitmap的加载,Activity的泄露,webview内存等。图片的内存问题,是很多Android应用,特别是电商APP需要首要关注的问题。那如何简单的分析出内存中Bitmap的情况,这里提供一个工具。借助leakcanary的思路,通过分析内存堆dump文件中android.graphics.Bitmap对象的情况,将内存中Bitmap对象批量保存到图片文件中,这样就可以直观的看到内存中加载的Bitmap个数、内容和大小,进而分析可能的内存问题。

9210dbadc28f8c8194508ad09056c094.png

94dd36db651a577c30c6e674052c34f8.png

示例

以分析蘑菇街APP内存中bitmap为例:

先使用Android monitor dump hprof

hprof-conv做格式转换

java -jar ./bitmap-analyzer-0.0.1-SNAPSHOT.jar /Users/Ivonhoe/hprof/com.mogujie-conv.hprof 蘑菇街

参数说明:

参数1:需要处理hprof文件的绝对路径

参数2:图片输出的文件夹名称,在hprof文件目录中创建该文件夹,缺省时直接会在hprof文件目录输出文件

输出说明

0de206499448f8299290fde8801d5125.png

大小排序.txt 按照图片像素尺寸,从大到小排序

个数排序.txt 按照相同尺寸图片个数,从大到小排序

文件名 width*height_index.png

Jar包地址

六、参考文档



推荐阅读
  • 下载完成之后解压提取jl1.0.0.1.jar这里写图片描述将jl1.0.0.1.jar拷贝到项目中,并添加到Library这里写图片描述4.源代码Tip:由于工程名 ... [详细]
  • Hbase 的伪分布部署、shell基本操作及hbase相关理念
    1,HBase的的的的伪分布式配置-对zookeeper的配置,这个前面配置过,修改zoo.cfg文件,指定zookeeper的主入口-配置的HBase的的:进入optmo ... [详细]
  • Maven 无法打包jar到 Tomcat
    今天新来的同事,让他调试短信验证的接口。跟我说添加的aliyun的短信验证服务无法在tomcat上运行。然后给我看了报错信息:java.lang.NoClassDefFoundEr ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • etc杂七杂八的配置文件etc不是什么缩写,是andsoon(等等)的意思来源于法语的etcetera翻译成中文就是等等的意思.至于为什么在etc下面存放配置文件& ... [详细]
  • 在Android源码环境下编译系统App使用第三方jar包的方法(备忘)
    1将要使用的jar包放入App的根目录,即Android.mk所在目录2按如下方式编写Android.mk文件(########之间的行用于编译和使用jar包)LOCAL_PATH:$(ca ... [详细]
  • 编程语言是从哪蹦出来的——大型伦理寻根现场
    Hello,我是Alex007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫Alex的人太多了,再加上每天007的生活,Alex007就诞生了。聊一聊编程到底是啥,怎 ... [详细]
  • 目录结构如下:Nginx基础知识NginxHTTP服务器的特色及优点Nginx的主要企业功能Nginx作为web服务器的主要应用场景包括:Nginx的安装安装环境 ... [详细]
  • 各个组件confspark-env.sh配置spark的环境变量confspark-default.conf配置spark应用默认的配置项和spark-env.sh有重合之处,可在 ... [详细]
  • MQ的使用
    安装环境:linuxredhatactivemq版本:5.8.01.从http:activemq.apache.orgdownload.html地址下载 ... [详细]
  • Android JNI学习之Concepts
    2019独角兽企业重金招聘Python工程师标准ConceptsBeforeBeginningThisguideassumesthatyouare:Alreadyfamili ... [详细]
  • 本文整理了Java中com.jogamp.opengl.GLDrawable.setRealized()方法的一些代码示例,展示了GLDrawable.se ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
author-avatar
手机用户2502928053
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有