Android内存优化(使用SparseArray和ArrayMap代替HashMap)

出处:Sunzxyong

HashMap

HashMap内部是使用一个默认容量为16的数组来存储数据的,而数组中每一个元素却又是一个链表的头结点,所以,更准确的来说,HashMap内部存储结构是使用哈希表的拉链结构(数组+链表),如图:
这种存储数据的方法叫做拉链法
这里写图片描述
且每一个结点都是Entry类型,那么Entry是什么呢?我们来看看HashMap中Entry的属性:

final K key;
V value;
final int hash;
HashMapEntry<K, V> next;
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

从中我们得知Entry存储的内容有key、value、hash值、和next下一个Entry,那么,这些Entry数据是按什么规则进行存储的呢?就是通过计算元素key的hash值,然后对HashMap中数组长度取余得到该元素存储的位置,计算公式为hash(key)%len,比如:假设hash(14)=14,hash(30)=30,hash(46)=46,我们分别对len取余,得到
hash(14)%16=14,hash(30)%16=14,hash(46)%16=14,所以key为14、30、46的这三个元素存储在数组下标为14的位置,如:
这里写图片描述
从中可以看出,如果有多个元素key的hash值相同的话,后一个元素并不会覆盖上一个元素,而是采取链表的方式,把之后加进来的元素加入链表末尾,从而解决了hash冲突的问题,由此我们知道HashMap中处理hash冲突的方法是链地址法,在此补充一个知识点,处理hash冲突的方法有以下几种:

  1. 开放地址法
  2. 再哈希法
  3. 链地址法
  4. 建立公共溢出区

讲到这里,重点来了,我们知道HashMap中默认的存储大小就是一个容量为16的数组,所以当我们创建出一个HashMap对象时,即使里面没有任何元素,也要分别一块内存空间给它,而且,我们再不断的向HashMap里put数据时,当达到一定的容量限制时(这个容量满足这样的一个关系时候将会扩容:HashMap中的数据量>容量*加载因子,而HashMap中默认的加载因子是0.75),HashMap的空间将会扩大,而且扩大后新的空间一定是原来的2倍,我们可以看put()方法中有这样的一行代码:

int newCapacity = oldCapacity * 2;
  • 1
  • 1

所以,重点就是这个,只要一满足扩容条件,HashMap的空间将会以2倍的规律进行增大。假如我们有几十万、几百万条数据,那么HashMap要存储完这些数据将要不断的扩容,而且在此过程中也需要不断的做hash运算,这将对我们的内存空间造成很大消耗和浪费,而且HashMap获取数据是通过遍历Entry[]数组来得到对应的元素,在数据量很大时候会比较慢,所以在Android中,HashMap是比较费内存的,我们在一些情况下可以使用SparseArray和ArrayMap来代替HashMap。

SparseArray

SparseArray比HashMap更省内存,在某些条件下性能更好,主要是因为它避免了对key的自动装箱(int转为Integer类型),它内部则是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,为了优化性能,它内部对数据还采取了压缩的方式来表示稀疏数组的数据,从而节约内存空间,我们从源码中可以看到key和value分别是用数组表示:

    private int[] mKeys;private Object[] mValues;
  • 1
  • 2
  • 1
  • 2

我们可以看到,SparseArray只能存储key为int类型的数据,同时,SparseArray在存储和读取数据时候,使用的是二分查找法,我们可以看看:

 public void put(int key, E value) {int i = ContainerHelpers.binarySearch(mKeys, mSize, key);...}public E get(int key, E valueIfKeyNotFound) {int i = ContainerHelpers.binarySearch(mKeys, mSize, key);...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

也就是在put添加数据的时候,会使用二分查找法和之前的key比较当前我们添加的元素的key的大小,然后按照从小到大的顺序排列好,所以,SparseArray存储的元素都是按元素的key值从小到大排列好的。
而在获取数据的时候,也是使用二分查找法判断元素的位置,所以,在获取数据的时候非常快,比HashMap快的多,因为HashMap获取数据是通过遍历Entry[]数组来得到对应的元素。

添加数据

public void put(int key, E value)
  • 1
  • 1

删除数据

 public void remove(int key)
  • 1
  • 1

or

public void delete(int key)
  • 1
  • 1

其实remove内部还是通过调用delete来删除数据的

获取数据

public E get(int key)
  • 1
  • 1

or

public E get(int key, E valueIfKeyNotFound)
  • 1
  • 1

该方法可设置如果key不存在的情况下默认返回的value

特有方法

在此之外,SparseArray还提供了两个特有方法,更方便数据的查询:
获取对应的key:

public int keyAt(int index)
  • 1
  • 1

获取对应的value:

public E valueAt(int index)
  • 1
  • 1

SparseArray应用场景:

虽说SparseArray性能比较好,但是由于其添加、查找、删除数据都需要先进行一次二分查找,所以在数据量大的情况下性能并不明显,将降低至少50%。

满足下面两个条件我们可以使用SparseArray代替HashMap:

  • 数据量不大,最好在千级以内
  • key必须为int类型,这中情况下的HashMap可以用SparseArray代替:
HashMap<Integer, Object> map = new HashMap<>();
用SparseArray代替:
SparseArray<Object> array = new SparseArray<>();
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

ArrayMap

这个api的资料在网上可以说几乎没有,然并卵,只能看文档了
ArrayMap是一个<key,value>映射的数据结构,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%。

添加数据

public V put(K key, V value)
  • 1
  • 1

获取数据

public V get(Object key)
  • 1
  • 1

删除数据

public V remove(Object key)
  • 1
  • 1

特有方法

它和SparseArray一样同样也有两个更方便的获取数据方法:

public K keyAt(int index)
public V valueAt(int index)
  • 1
  • 2
  • 1
  • 2

ArrayMap应用场景

  • 数据量不大,最好在千级以内
  • 数据结构类型为Map类型
ArrayMap<Key, Value> arrayMap = new ArrayMap<>();
  • 1
  • 1

【注】:如果我们要兼容aip19以下版本的话,那么导入的包需要为v4包

import android.support.v4.util.ArrayMap;
  • 1
  • 1

总结

SparseArray和ArrayMap都差不多,使用哪个呢?
假设数据量都在千级以内的情况下:

1、如果key的类型已经确定为int类型,那么使用SparseArray,因为它避免了自动装箱的过程,如果key为long类型,它还提供了一个LongSparseArray来确保key为long类型时的使用

2、如果key类型为其它的类型,则使用ArrayMap

转载于:https://www.cnblogs.com/chenxing818/p/5978610.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/417905.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS2010与QT的集成开发环境

http://blog.csdn.net/hbsong75/article/details/9293773 QT与Java有点类似&#xff0c;也是一种跨平台的软件&#xff08;当然在windows平台和Linux平台需要安装相应的QT开发环境和运行库&#xff0c;类似于JAVA在不同平台下的虚拟机JVM环境&#xff09;&#xff0c;因此对于某…

各种排序笔记---基于非比较排序部分

在计算机科学中&#xff0c;排序是一门基础的算法技术&#xff0c;许多算法都要以此作为基础&#xff0c;不同的排序算法有着不同的时间开销和空间开销。排序算法有非常多种&#xff0c;如我们最常用的快速排序和堆排序等算法&#xff0c;这些算法需要对序列中的数据进行比较&a…

SharePoint Framework 构建你的第一个web部件(三)

&#xfeff;&#xfeff;博客地址&#xff1a;http://blog.csdn.net/FoxDave本篇接上一讲&#xff0c;我们一起来看一下如何部署和测试本地开发的web部件。在SharePoint中预览web部件SharePoint工作台在SharePoint中被承载&#xff0c;用来在开发环境预览和测试本地web部件。它…

mysql limit asc_MySql sql优化之order by desc/asc limit M-阿里云开发者社区

Order by desc/asc limit M是我在mysql sql优化中经常遇到的一种场景&#xff0c;其优化原理也非常的简单&#xff0c;就是利用索引的有序性&#xff0c;优化器沿着索引的顺序扫描&#xff0c;在扫描到符合条件的M行数据后&#xff0c;停止扫描&#xff1b;看起来非常的简单&am…

Spring 4 官方文档学习(十)数据访问之JDBC

说明&#xff1a;未修订版&#xff0c;阅读起来极度困难 1、Spring框架JDBC的介绍 Spring JDBC - who does what? 动作Spring你定义连接参数 是打开连接是 指定SQL语句 是声明参数&#xff0c;提供参数值 是准备、执行语句是 迭代结果&#xff08;如果有&#xff09;是 操作每…

协方差

协方差一般用来研究诸多实验中各个变量之间的关系。举个例子来说&#xff0c;有n个实验&#xff0c;每个实验得到两个数据&#xff0c;分别为变量x1和变量x2。设n 7。这七组实验得到的数据分别为&#xff1a; (3,5), (4,5.5),(2,4),(6,7),(8,10),(2,5),(5,7.5) 用MATLAB…

行为类模式(二):命令(Command)

定义 将一个请求封装成一个对象&#xff0c;从而让你使用不同的请求把客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能。 UML 优点 能比较容易的设计一个命令队列可以较容易的将命令加入日志允许接收请求的一方是否处理请求可以容…

win7 nginx mysql php_windows7配置Nginx+php+mysql的详细教程

最近在学习PHP&#xff0c;想把自己的学习经历记录下来&#xff0c;并写一些经验&#xff0c;仅供参考交流。此文适合那些刚刚接触PHP&#xff0c;想要学习并想要自己搭建NginxPHPMysqL环境的同学。当然&#xff0c;你也可以选择集成好的安装包&#xff0c;比如 wamp等&#xf…

我的虚拟化设想(My virtualization vision)

王洪岐&#xff08;Wang Hongqi&#xff09; 当前的服务器虚拟化技术所虚拟的操作系统都是完整的操作系统&#xff0c;我认为这样会在一定程度上造成了资源的浪费和技术难度的增加&#xff1a;多个操作系统就有多个操作硬件设备的操作程序&#xff0c;虚拟平台要在操作系统底层…

Kmplayer播放器 绿色免安装版 2016 中文版

软件名称&#xff1a; Kmplayer播放器 绿色免安装版 软件语言&#xff1a; 简体中文 授权方式&#xff1a; 免费软件 运行环境&#xff1a; Win 32位/64位 软件大小&#xff1a; 42.8MB 图片预览&#xff1a; 软件简介: Kmplayer播放器绿色免安装版&#xff0c;多功能的影音播放…

什么是反向代理,如何区别反向与正向代理

转自&#xff1a;http://blog.csdn.NET/shixing_11/article/details/7106241 一直对反射代理的反向不知道如何理解&#xff0c;经过百度知道&#xff0c;再结合下面这幅图&#xff0c;总算弄清楚一点了。简单的说从一个局域网出来到服务端为正向&#xff0c;从客户端要进入一个…

java socket 浏览器_Socket实现Java和浏览器交互。

昨天写了段小程序&#xff0c;现贴出来看看。以下是socket的简单介绍。获取两台联通的机器之间的IP和端口号等信息。import java.io.IOException;import java.net.Socket;public class SockerDemo {public static void main(String[] args) throws IOException {Socket socket …

HashMap和ConcurrentHashMap的区别,HashMap的底层源码。

Hashmap本质是数组加链表。根据key取得hash值&#xff0c;然后计算出数组下标&#xff0c;如果多个key对应到同一个下标&#xff0c;就用链表串起来&#xff0c;新插入的在前面。 ConcurrentHashMap&#xff1a;在hashMap的基础上&#xff0c;ConcurrentHashMap将数据分为多个s…

[水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API

问题 怎么样将 Asp.Net Web Api 加入到现有的 Asp.Net MVC 项目中 解决方案 在 Visual Studio 2012 中就已经把 Asp.Net Web Api 自动地整合到了 MVC 项目模板中。自 Visual Studio 2013 以后&#xff0c;创建 ASP.Net Web应用程序使用的是一种新的"One ASP.NET"项目…

java io流文件损坏_java使用io流下载.docx. xlsx文件,出现文件损坏提示

介绍在使用io流下载服务器上的资源文件时&#xff0c;出现以下提示&#xff1a;但是选择“是”后文件可以正常打开参考 代码如下&#xff1a;[codesyntax lang"java"]RequestMapping(value "downLoadInstruction")public void downLoadInstruction(HttpSe…

java 内存堆和栈_java堆内存和栈内存的处理

前段时间学习二叉树在处理删除操作的时候遇到一个头疼的问题&#xff1a;删除节点的时候明明已经置null了可树上该节点依旧存在&#xff0c;还必须执行node.father.left null;才可以删除node节点&#xff0c;寻找了一下原因发现还是因为对java内存管理理解不够深入。代码如下&…

python基础(十三)

项目实战&#xff1a;运维堡垒机开发 前景介绍 到目前为止&#xff0c;很多公司对堡垒机依然不太感冒&#xff0c;其实是没有充分认识到堡垒机的IT管理中的重要作用的&#xff0c;很多人觉得&#xff0c;堡垒机就是跳板机&#xff0c;其实这个认识是不全面的&#xff0c;跳板功…

java面向_java是面向什么的语言?

Java是一门面向对象编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表&#xff0c;极好地实现了面向对象理论&#xff0c;…

java流的应用_Java中I/O流的应用

Java中I/O流的应用iLeGeNDpackagecom.hp.io;/** I/O流的应用 * 实现目标&#xff1a; * 首先创建一个文件 * 通过键盘向文件添加内容 * 然后把文件的内容打印到控制台 * */import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import ja…

PHP的反射类ReflectionClass、ReflectionMethod使用实例

PHP5 具有完整的反射API&#xff0c;添加对类、接口、函数、方法和扩展进行反向工程的能力。 反射是什么&#xff1f; 它是指在PHP运行状态中&#xff0c;扩展分析PHP程序&#xff0c;导出或提取出关于类、方法、属性、参数等的详细信息&#xff0c;包括注释。这种动态获取的信…