在很多android app开发中经常使用HashMap的集合,其实使用使用SparseArray看到的不是太多,很多Java书上介绍的也不是太多.只有查看android源码才能够发现这个东西到处在使用.
下面是其他博客上面的一个分析:
二维数组数据保存组织结构如下:
在此数组中,共有63个空间,但却只使用了5个元素,造成58个元素空间的浪费.使用稀疏数组重新来定义这个数组
SparseArray 集合是:
经过压缩后,占用的空间就大大缩小了很多.其中在稀疏数组中第一部分所记录的是原数组的列数和行数以及元素使用的个数、第二部分所记录的是原数组中元素的位置和内容。经过压缩之后,原来需要声明大小为63的数组,而使用压缩后,只需要声明大小为6*3的数组,仅需18个存储空间.
上面的可以参见:http://www.cnblogs.com/adison/p/3615375.html
具体的做一个android工程测试:
<1> : 新建工程如下:
<2> : 具体程序代码如下:
DurianMainActivity.java
package env.durian.duriantypearray; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.util.HashMap; import java.util.Iterator; import java.util.Set; public class DurianMainActivity extends ActionBarActivity implements View.OnClickListener { private final static String TAG="DurianMainActivity"; private Button mHashMapButton; private TextView mHashMapText; private Button mSparseButton; private TextView mSparseText; private Button mGcButton; private HashMap mHashMap; private SparseArray mSparseArray; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.durian_main); mHashMap=new HashMap<Integer,String>(); mHashMapButton=(Button)findViewById(R.id.hashbutton); mHashMapButton.setOnClickListener(this); mSparseArray=new SparseArray<String>(); mSparseButton=(Button)findViewById(R.id.sparsebutton); mSparseButton.setOnClickListener(this); mGcButton=(Button)findViewById(R.id.gcbutton); mGcButton.setOnClickListener(this); } private void OOMSparseArray(){ for(int i=0;i<10000;i++){ mSparseArray.put(i,"arrary : "+i); } String value=""; for(int j=0;j<mSparseArray.size();j++){ value=(String)mSparseArray.valueAt(j); Log.i(TAG,"value : "+value); } } private void OOMHashMap(){ //add 1000 elements for(int i=0;i<10000;i++){ mHashMap.put(i,"number : "+i); } String value=""; Set<Integer> set=mHashMap.keySet(); for(Iterator<Integer> iter=set.iterator();iter.hasNext();){ Integer it=iter.next(); value=(String)mHashMap.get(it); Log.i(TAG,"value : "+value); } } @Override public void onClick(View v) { int id=v.getId(); switch (id){ case R.id.hashbutton: OOMHashMap(); break; case R.id.sparsebutton: OOMSparseArray(); break; case R.id.gcbutton: System.gc(); break; default: break; } } }
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/hashtext" android:text="" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hashmap" android:id="@+id/hashbutton"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/sparsetext" android:text="" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="sparsearray" android:id="@+id/sparsebutton"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="raise GC" android:id="@+id/gcbutton"/> </LinearLayout>
<3> : 打开Android Studio 的Memory Monitor的查看页面:
操作之前的内存使用情况:
操作HashMap的那个按钮,递减让其执行:
前后嘴鼻,刚开始使用量是8.34M,执行后直接上升到11.76M,图形中有斜坡处,相差3.42M.
再测试一下SparseArray的:
初始使用值是8.42M,点击SparseArray按钮:
操作后变为11.40M,与前面相差:2.98M,与前面的3.42M相差0.44M,显然很明显.
<4> : 测试程序中还添加了一个GC触发的按钮,人为主动触发GC,提交给系统释放内存,从上面的图形可知,操作其中一个后,Free剩余非常少了,已经没有空间再执行一次同样的操作了,那么在上面的基础上,再执行一次HashMap的操作,会变成:
有一个锯齿状的产生,释放出两个信号:第一个信号是会发觉整个可支配的空间变大了,达到16M了,即Free空间变大了,对应浅色区域,同时导致系统释放了一部分已经使用的内存大小,所以使用的神色区域会下降.
这个时候再点击GC按钮,人为要求系统进行内存回收:
上面有向上的斜坡,感觉GC也需要增加内存使用量.
但是这种情况不是一定会出现的,如果系统能够及时释放使用的内存,那么系统就不会加大到16M内存空间给APP使用,所以可能有三种情况:
<1> : 系统立即释放内存,不加大APP的分配空间;
<2> : 系统不能够立即释放内存,加大分配空间的同时也多多少少的释放一部分空间,见上图;
<3> : 系统完全没有及时释放内存,直接分配了更大的空间给app使用.