Bitmap分析

在bitmap中用一位来表示page是否被占用,1表示被占用,0表示没被占用,计算机里面处理的位数最少的变量是byte,所以也就是8位做为一个整体来对待,8位表示的整数是从0到255,

firstHoleSize [] lastHoleSize [] maxHoleSize [] maxHoleOffset [] 是四个固定的数组,每个数组都有256个元素,对应从0到255的整数,每个整数的二进制代表的页面被占用情况

举例来说: 00001010 代表十进制的10

firstHoleSize [] 表示从右到左的,未被占用的页面有多少个,只要末位为是1,那么肯定没有hole,所以奇数全为0,firstHoleSize [10] = 1

lastHoleSize [] ,表示从左到右,未被占用的页面多少个,只要最左位为1,那是肯定没有hole,所以大于128的全是0, lastHoleSize [10] = 4

 

maxHoleSize [] ,表示连续的最大的Hole是多少个页面,maxHoleSize [10] = 4

maxHoleOffset [] 是和 maxHoleSize [] 一起使用的,表示从左到右,最大的Hole的位置,maxHoleOffset [10] = 4

 

const size_t dbAllocationQuantumBits = 4;
const size_t dbAllocationQuantum = 1 << dbAllocationQuantumBits;
const size_t dbPageBits = 12;
const size_t dbPageSize = 1 << dbPageBits;
const size_t dbIdsPerPage = dbPageSize / sizeof(oid_t);
const size_t dbHandlesPerPage = dbPageSize / sizeof(offs_t);
const size_t dbHandleBits = 1 + sizeof(offs_t)/4; // log(sizeof(offs_t))
const size_t dbBitmapSegmentBits = dbPageBits + 3 + dbAllocationQuantumBits;
const size_t dbBitmapSegmentSize = 1 << dbBitmapSegmentBits;
const size_t dbBitmapPages = 1 << (dbDatabaseOffsetBits-dbBitmapSegmentBits);
const size_t dbDirtyPageBitmapSize = 1 << (dbDatabaseOidBits-dbPageBits+dbHandleBits-3);

在fastdb中,bitmap中的每一位,表示两个字节,就是16位:

const size_t dbAllocationQuantumBits = 4;
const size_t dbAllocationQuantum = 1 << dbAllocationQuantumBits;

每一个page中,有4096个byte,:

const size_t dbPageBits = 12;
const size_t dbPageSize = 1 << dbPageBits;

每个bitmap的page,能表示的存储空间总数量为2的(12 + 3 + 4)次幂:

const size_t dbBitmapSegmentBits = dbPageBits + 3 + dbAllocationQuantumBits;
const size_t dbBitmapSegmentSize = 1 << dbBitmapSegmentBits

在32位的系统中(dbDatabaseOffsetBits = 32),所需要的bitmap的总的page数就为,2的32次幂除以上面那个数,也就是8192个页面,

const size_t dbBitmapPages = 1 << (dbDatabaseOffsetBits-dbBitmapSegmentBits);

fast在初始化过程中,默认了8K的bitmap页面,但并没有实际的分配,只是指定了个数

在内存中还存在一个结构,用来保存在事务过程中哪个页面被修改了,也是用bitmap来实现的,它需要页面的总个数,对于32位的系统,每个页面是12位,每个字节可表示8位,(每个oid须用四位表示,或是每个页面只能存dbIdsPerPage 个oid),这个部分主要是从oid到页面的快速变换:

const size_t dbDirtyPageBitmapSize = 1 << (dbDatabaseOidBits-dbPageBits+dbHandleBits-3);

class dbMonitor {

。。。。。。。

int4 dirtyPagesMap[dbDirtyPageBitmapSize/4];

。。。。。。

一起使用

 

在空间的分配时,先看看是不是有以前释放的满足要求,没有的话就从未分配的分配,分配函数只要把前面几个宏定义和数组看明白,还是比较好理解的,主要就是修改bitmap里面字节的每一位

bitmap里面的每一位,代表硬盘上一个16字节的空间是否被使用,不是一个4096个字节的页面,

代表页面的只有是否表示页面被修改过的另一个结构,dbMonitor->dirtyPagesMap[],不要搞混,

 

 

 

在数据库运行一段时间后,bitmap中和页面将变得不再连续,因为不停的拷贝造成的,index 和 shadowIndex还是连续的

在每次修改bitmap之前,会把它拷贝一份,在拷贝的那份上修改,

拷贝主要是在dbRecord* putRow(oid_t oid) 和 byte* put(oid_t oid) 这两个函数里面实现的,名字比较怪

<think>好的,我现在需要帮用户介绍一下安卓中的Bitmap内存分析。首先,我得回忆一下自己之前学过的相关知识,确保准确无误。Bitmap在安卓中确实是一个比较重要的部分,同时也是内存消耗的大户,所以分析它的内存使用情况对于优化应用性能很关键。 首先,我应该从Bitmap的内存管理机制开始讲起。记得安卓的Bitmap内存分为两部分:Java层和Native层。在早期的版本中,比如Android 3.0之前,Bitmap的像素数据是存放在Java堆中的,但之后改到了Native堆,这样可以避免Java堆的内存限制,减少GC的影响。不过,从Android 8.0开始,又改回了Java堆,这可能是因为内存管理的优化或者其他原因。我需要确认一下这些版本变化的具体细节,避免给用户错误的信息。 接下来,用户可能需要知道如何计算Bitmap占用的内存。这里的关键是内存的计算公式:内存大小 = 图片宽度 × 图片高度 × 每个像素占用的字节数。每个像素的字节数取决于Bitmap的配置,比如ARGB_8888是4字节,RGB_565是2字节,ALPHA_8是1字节。需要注意的是,这里计算的是解码后的内存占用,和图片文件的大小不同,比如一张PNG图片文件可能只有100KB,但解码成Bitmap后可能占用几MB的内存。这点需要强调,因为很多开发者容易混淆这两个概念。 然后,用户可能想知道如何分析Bitmap的内存使用情况。这时候需要介绍一些工具,比如Android Studio的Profiler,可以实时查看内存分配情况,还有Android的API,如Bitmap.getAllocationByteCount()来获取实际分配的内存。另外,命令行工具如adb shell dumpsys meminfo可以用来查看进程的内存信息,其中Bitmap相关的部分需要关注。 另外,内存泄漏的问题也是常见的。比如在Activity中加载大图,但没有及时回收,或者在列表中使用Bitmap没有正确复用,导致内存不断增长。这时候需要提到常见的泄漏场景和解决方法,比如使用弱引用、及时recycle(虽然现在可能不推荐直接调用,但需要说明版本差异),以及使用inBitmap属性来复用内存,特别是在列表或频繁创建Bitmap的场景下。 还有需要考虑的是不同屏幕密度下的内存问题。比如,图片放在不同的drawable目录下,系统会根据设备密度进行缩放,导致内存增加。例如,一张放在drawable-xxhdpi的图片在hdpi设备上会被放大,从而增加内存占用。这时候应该建议将图片放在合适的目录或者使用矢量图来避免这个问题。 另外,可能需要提到一些优化策略,比如使用合适的Bitmap.Config,根据需求调整图片尺寸(采样压缩),使用图片缓存库(如Glide、Picasso)来自动处理内存问题,以及如何正确管理Bitmap的生命周期,避免在不需要的时候仍然持有引用。 还有,在分析内存问题时,要考虑到不同Android版本之间的差异,比如之前提到的Native堆和Java堆的变化,以及API的兼容性处理。例如,在Android 8.0及以上版本,Bitmap的内存又回到了Java堆,这可能影响到内存分析的方法和工具的使用。 总结下来,我需要分步骤地介绍Bitmap内存的组成部分、计算方法、分析工具、常见问题及优化策略,确保用户能够系统地理解如何分析和处理Bitmap相关的内存问题。同时,要注意用词准确,避免技术错误,并给出实际的例子和建议,帮助用户更好地应用这些知识。</think>### 安卓 Bitmap 内存分析指南 #### 一、Bitmap 内存管理机制 1. **内存分布** - **Android 3.0 之前**:Bitmap 像素数据存储在 Java 堆,受 `GC` 影响大,易触发 `OOM`。 - **Android 3.0~7.x**:像素数据移至 Native 堆,Java 层仅保留引用,减少 `GC` 压力。 - **Android 8.0+**:像素数据回归 Java 堆(通过 `NativeAllocationRegistry` 管理),避免 Native 内存泄漏。 2. **内存计算公式** $$ \text{内存大小} = \text{宽度} \times \text{高度} \times \text{每像素字节数} $$ - 不同 `Bitmap.Config` 的每像素字节数: - `ARGB_8888`:4 字节 - `RGB_565`:2 字节 - `ALPHA_8`:1 字节 **示例**:一张 1920×1080 的图片使用 `ARGB_8888` 配置,内存占用为: $$ 1920 \times 1080 \times 4 = 8,294,400 \text{字节} \approx 7.91 \text{MB} $$ --- #### 二、内存分析工具 1. **Android Profiler** - 查看实时内存分配,定位 Bitmap 内存峰值。 - 支持堆转储(Heap Dump),分析 Bitmap 对象数量和占用空间。 2. **代码 API** ```kotlin val bitmapAllocationSize = bitmap.allocationByteCount // 获取实际分配内存 ``` 3. **命令行工具** ```bash adb shell dumpsys meminfo <package_name> # 输出中包含 "Graphics" 部分,显示 Bitmap 总内存 ``` --- #### 三、常见问题与优化 1. **内存泄漏场景** - **未释放 Activity/Fragment 中的 Bitmap**:在 `onDestroy()` 中调用 `recycle()`(仅对 Native 堆有效)。 - **列表未复用 Bitmap**:使用 `RecyclerView` + `BitmapPool`(如 Glide 内置复用机制)。 2. **屏幕密度适配问题** - 图片放在低密度目录(如 `drawable-mdpi`)时,在高密度设备上会放大,导致内存增加。 - **解决方案**: - 将图片放在 `drawable-nodpi` 目录,禁止系统缩放。 - 使用矢量图(VectorDrawable)或 WebP 格式。 3. **优化策略** - **采样压缩**:通过 `inSampleSize` 降低解码后的尺寸。 ```kotlin val options = BitmapFactory.Options() options.inSampleSize = 2 // 宽高缩小为 1/2 ``` - **复用 Bitmap**:Android 4.4+ 使用 `inBitmap` 属性复用内存。 - **配置选择**:根据需求选择 `RGB_565`(无透明度需求)或 `ARGB_4444`。 - **图片库推荐**:Glide/Picasso 自动处理生命周期和内存复用。 --- #### 四、扩展注意事项 - **大图加载**:使用 `RegionDecoder` 分块加载局部区域。 - **Native 内存监控**:Android 8.0 前需关注 `adb shell procrank` 或 `DDMS` 的 Native 堆数据。 - **API 兼容性**:`inBitmap` 在 Android 4.4 前要求大小严格匹配,4.4+ 支持更大 Bitmap 复用。 --- 通过以上分析工具和优化方法,可有效定位并解决 Bitmap 内存问题,提升应用性能和稳定性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值