热门标签 | 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包地址

六、参考文档



推荐阅读
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • Spring Data JdbcTemplate 入门指南
    本文将介绍如何使用 Spring JdbcTemplate 进行数据库操作,包括查询和插入数据。我们将通过一个学生表的示例来演示具体步骤。 ... [详细]
  • 为什么多数程序员难以成为架构师?
    探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 本文介绍了在 Java 编程中遇到的一个常见错误:对象无法转换为 long 类型,并提供了详细的解决方案。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 原文网址:https:www.cnblogs.comysoceanp7476379.html目录1、AOP什么?2、需求3、解决办法1:使用静态代理4 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 类加载机制是Java虚拟机运行时的重要组成部分。本文深入解析了类加载过程的第二阶段,详细阐述了从类被加载到虚拟机内存开始,直至其从内存中卸载的整个生命周期。这一过程中,类经历了加载(Loading)、验证(Verification)等多个关键步骤。通过具体的实例和代码示例,本文探讨了每个阶段的具体操作和潜在问题,帮助读者全面理解类加载机制的内部运作。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 本文详细介绍了如何在Java Web服务器上部署音视频服务,并提供了完整的验证流程。以AnyChat为例,这是一款跨平台的音视频解决方案,广泛应用于需要实时音视频交互的项目中。通过具体的部署步骤和测试方法,确保了音视频服务的稳定性和可靠性。 ... [详细]
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社区 版权所有