http://blog.csdn.net/droidpioneer/article/details/6758057

操作过Android手机的朋友应该对在待机界面拖动图标的交互效果都有比较深刻的印象,比如说,当把图标拖动起来,图标会悬浮并随着拖动变换位置,当拖动释放后,图标会自动的寻找附近合适的空白网格位置。Android在实现这个效果的过程中采用了很多编程技巧,本文着重论述的VacantCell缓存就很具有代表性。

VacantCell缓存主要是对同一种类型对象的缓存机制,这种机制的目的是复用已经分配过但已过期的对象,从而避免频繁的new新的对象。我们知道对象分配是一件比较耗费系统资源的事情,在需要频繁、大量的分配对象的时候Android平台很可能出现堆内存不足进而导致系统变慢、应用报错重启等严重问题。用户在待机界面拖动图标是很频繁的事情,而Android的屏幕中空白网格的寻址算法就采用了这种VacantCell缓存来避免频繁new大量新的对象。

VacantCell类的实现其实很简单,就不到50行实现代码:

view plaincopy to clipboard
  1. static final class VacantCell {
  2. int cellX;
  3. int cellY;
  4. int spanX;
  5. int spanY;
  6. // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
  7. // like a reasonable compromise given the size of a VacantCell and
  8. // the fact that the user is not likely to touch an empty 4x4 grid
  9. // very often
  10. private static final int POOL_LIMIT = 100;
  11. private static final Object sLock = new Object();
  12. private static int sAcquiredCount = 0;
  13. private static VacantCell sRoot;
  14. private VacantCell next;
  15. static VacantCell acquire() {
  16. synchronized (sLock) {
  17. if (sRoot == null) {
  18. return new VacantCell();
  19. }
  20. VacantCell info = sRoot;
  21. sRoot = info.next;
  22. sAcquiredCount--;
  23. return info;
  24. }
  25. }
  26. void release() {
  27. synchronized (sLock) {
  28. if (sAcquiredCount < POOL_LIMIT) {
  29. sAcquiredCount++;
  30. next = sRoot;
  31. sRoot = this;
  32. }
  33. }
  34. }
  35. @Override
  36. public String toString() {
  37. return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
  38. ", spanY=" + spanY + "]";
  39. }
  40. }
[java] view plaincopy
  1. static final class VacantCell {
  2. int cellX;
  3. int cellY;
  4. int spanX;
  5. int spanY;
  6. // We can create up to 523 vacant cells on a 4x4 grid, 100 seems
  7. // like a reasonable compromise given the size of a VacantCell and
  8. // the fact that the user is not likely to touch an empty 4x4 grid
  9. // very often
  10. private static final int POOL_LIMIT = 100;
  11. private static final Object sLock = new Object();
  12. private static int sAcquiredCount = 0;
  13. private static VacantCell sRoot;
  14. private VacantCell next;
  15. static VacantCell acquire() {
  16. synchronized (sLock) {
  17. if (sRoot == null) {
  18. return new VacantCell();
  19. }
  20. VacantCell info = sRoot;
  21. sRoot = info.next;
  22. sAcquiredCount--;
  23. return info;
  24. }
  25. }
  26. void release() {
  27. synchronized (sLock) {
  28. if (sAcquiredCount < POOL_LIMIT) {
  29. sAcquiredCount++;
  30. next = sRoot;
  31. sRoot = this;
  32. }
  33. }
  34. }
  35. @Override
  36. public String toString() {
  37. return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
  38. ", spanY=" + spanY + "]";
  39. }
  40. }

可以看到,VacantCell实际上是一个Java静态内部类,其外部类CellLayout.java的代码路径是\packages\apps\Launcher2\src\com\android\launcher2\CellLayout.java(具体如何下载Android gingerbread Launcher单个模块的下载方法见博文Android源码下载——用git clone实现单个目录下载)。

下面我们具体分析下VacantCell的缓冲机制是如何实现的。

cellX、cellY、spanX、spanY几个成员是空白网格的纵横索引号和占据相应单元网格数,我们这里可以不用关心。

POOL_LIMIT定义了可以缓存的VacantCell的最大值,正如注释所说,最多可以分配多达523个VacantCell对象,但是对于4X4的屏幕网格定义来说,100个的缓冲数应该是足够的了。也就是说,这个100的数值是一个经验值,我们可以根据实际情况作灵活修改。

sLock是一个Java Object对象,主要是拿来作同步控制的,我们可以不用关心。

sAcquiredCount是一个非常重要的变量,其实际上就是一个计数器,实时的统计当前缓存了多少个VacantCell对象值。根据这个计数器和POOL_LIMIT可以控制缓存对象不超过POOL_LIMIT的上限。

sRoot和next是缓存VacantCell对象链式存储的两个关键引用,分别表示VacantCell对象链表的表头和特定VacantCell对象链接的下一对象的引用。

好了,下面介绍VacantCell缓存的两个关键静态方法acquire()和非静态方法release()。

当需要VacantCell新对象的时候,Launcher会调用静态内部类的VacantCell的静态方法acquire()以获取新的VacantCell对象。请注意,这里获取新对象不是直接new一个VacantCell对象,而是acquire的。我们看acquire方法的内部,当sRoot为null的时候,是直接new VacantCell并直接return的,因为这个时候实际上还没有缓存可用;当sRoot不为null,这意味着已经有缓存的VacantCell对象了,那么直接从链表中取出sRoot指向的对象,并将sRoot所在对象指向的next作为新的表头sRoot,同时把sAcquiredCount计数减1。这实际上是一种典型的从链表中删除表头的操作,相信熟悉数据结构的朋友对此都不会陌生。

如果说acquire()方法提供的是如何利用VacantCell链式缓存,那么release()方法解决的就是如何构建VacantCell链式缓存的问题。我们看到,只有sAcquiredCount < POOL_LIMIT的前提下才会将VacantCell对象加入链式缓存。将当前VacantCell对象加入链式存储也很简单,将当前VacantCell对象的next指向原来的表头,将静态sRoot应用指向当前对象,同时sAcquiredCount加1。也就是说,这个操作其实就是把当前VacantCell对象插入VacantCell链表的表头。

那么如何使用这个VacantCell对象缓存呢?第一,当需要新的VacantCell对象的时候,通过调用VacantCell的静态方法acquire()来获取对象,而不是直接new VacantCell对象;第二,当一个VacantCell对象已经过期,不再需要的时候,调用该对象的release()方法将这个不再需要的对象加入缓存。

需要指出的是,如果直接new VacantCell对象也不会有直接的问题,只不过这意味着没有采用VacantCell缓存机制;如果一个对象不需要时不显示调用release()方法也不会有直接的问题,这意味着这个对象不会加入进VacantCell缓存链表,当没有链表各节点对象的引用关联,这个对象最终将被Android的Dalvik虚拟机当做垃圾自动回收。

本文详细分析了Android Launcher模块VacantCell缓存的实现原理,当我们需要频繁构造、释放大量的相同类型的Java对象的时候,我们考虑采用类似的缓存机制,这在某些场合下能有效的解决频繁分配对象导致的内存不足的问题。

转载于:https://www.cnblogs.com/greywolf/archive/2012/12/24/2831290.html

vacantcell缓存分析相关推荐

  1. android原理揭秘系列之VacantCell缓存

    2019独角兽企业重金招聘Python工程师标准>>> 操作过Android手机的朋友应该对在待机界面拖动图标的交互效果都有比较深刻的印象,比如说,当把图标拖动起来,图标会悬浮并随着 ...

  2. 多级缓存分析篇(二) 常用分布式锁分析

    上篇主要讲了日常经常使用的哪些redis包及其配置的差异,这篇对基于redis的分布式锁,主要分享下自定义锁和redisson锁的使用和分析. 1.(自定义)Redis分布式锁 对于redis来说,非 ...

  3. 【转载】基于AFNetWorking3.0的图片缓存分析

    原文出处:Yasin的简书 http://www.jianshu.com/p/b1045c3fc8d0 图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作. [TOC] 理论 不喜欢理论的可 ...

  4. iOS开发--基于AFNetWorking3.0的图片缓存分析

    图片在APP中占有重要的角色,对图片做好缓存是重要的一项工作.[TOC] 理论 不喜欢理论的可以直接跳到下面的Demo实践部分 缓存介绍 缓存按照保存位置可以分为两类:内存缓存.硬盘缓存(FMDB.C ...

  5. Pod进程内存缓存分析

    背景 在使用kubernetes过程中,可以通过kubectl top pod 命令可以查看到各个Pod内存使用情况,从而发现与Pod进程实际使用内存不一致,具体情况如下: Java应用部署在kube ...

  6. ThinkPhp5数据库缓存分析

    写项目的时候经常需要缓存,tp5框架自带了一个数据库缓存, 数据更新时自动删除缓存,不过在用的时候发现有时候数据更新了但缓存并没有删除,便查看了下tp5数据库缓存的实现方式. 缓存 假设,现在要查询一 ...

  7. 如何从你的缓存分析全世界

    文章出自:听云博客 这是我去年十一回来就开始计划的实验,重装系统之后将QQ存储文件的文件夹放到了我的备份盘里, QQ会把你的聊天记录和图片分开存储,而且群组和好友也是分开存放在两个文件夹里的,好友G: ...

  8. Android四级缓存,RecyclerView 源码四级缓存原理

    入口 我们从使用功能上去读取源码,通常的用法是这个样子 -> 我们设置layoutmanager,GridLayouManager 继承LinearLayoutManager,所以我们就Line ...

  9. Cachegrind:缓存和分支预测分析器

    目录 5.1.概观5.2.使用Cachegrind,cg_annotate和cg_merge 5.2.1.运行Cachegrind5.2.2.输出文件5.2.3.运行cg_annotate5.2.4. ...

最新文章

  1. 关于SAP的“Sort key 排序码”
  2. c语言设计第六章答案,c语言第六章 循环结构程序设计(习题册答案)
  3. ROS有三个层级的概念,分别是:文件系统级、计算图级和开源社区级
  4. auto cad 打印颜色变浅_CAD制图软件中如何设置CAD打印样式表(CTB)?
  5. java中add和addall区别,java中list的add与addall方法区别
  6. risc-v 编译 linux,linux - 如何为RISC-V编译Linux Kernel 4.20 - 堆栈内存溢出
  7. 【渝粤教育】电大中专跨境电子商务理论与实务 (30)作业 题库
  8. mac下charles使用教程
  9. javacpp-opencv图像处理系列:国内车辆牌照检测识别系统(万份测试车牌识别准确率99.7%以上,单次平均耗时39ms)...
  10. 使用Zend Expressive快速进行企业应用开发
  11. 微信小程序开发,微信小程序轻松实现微信支付及微信提现到零钱功能
  12. 通过url给action传中文参数乱码解决方案
  13. Codeforces Round #670 (Div. 2) D. Three Sequences(差分序列、数学思维分析)
  14. 中小学计算机听课记录表,小学听课记录表40篇
  15. python之scrapy:第一只spider
  16. 地图采集车的那些事 | 时间同步
  17. 个人信息为何到处“裸奔”?
  18. WireShark是什么?其作用有哪些?
  19. 《Kotlin从小白到大牛》第28章:项目实战1:开发PetStore宠物商店项目
  20. 松江区专利工作试点和示范企业认定政策解读

热门文章

  1. eclipse User Enties 顺序
  2. 如何判断一个网站是否被百度处罚中
  3. mysql 数据表操作 存储引擎介绍
  4. ThreadPoolExecuotor源码参考
  5. 多阶段构建Docker镜像
  6. vue,一路走来(10)--生产环境
  7. Git学习笔记------整理自廖雪峰官网教程
  8. NormalMap 贴图 [转]
  9. Kinect v2.0 for windows开发环境说明
  10. SQL语句修改主键列