Andoird优化,内存优化

laura107 8年前
   <p style="text-align:center"><img alt="Andoird优化,内存优化" src="https://simg.open-open.com/show/2a0568da12c0228b77f1f8f61a04c91a.png"></p>    <p style="text-align:center">内存管理</p>    <blockquote>     <p> </p>    </blockquote>    <p>但这也仅仅是为大家提供一些思路与较为全面的总结,算不上什么,希望有错误或问题在下面评论。</p>    <p>最后完结以后会将思维导图与优化框架整理出来,请期待。<br> <strong>如果程序会运行着崩溃、或者突然被系统杀死</strong>,那你就该继续往下看。</p>    <p style="text-align:center"><img alt="Andoird优化,内存优化" src="https://simg.open-open.com/show/8467558acc53b062f80e61e885acf419.png"></p>    <p>这是这章的思维导图,不过压缩严重,下面是样图,原图和源文件在最下方链接。还是值得下载的。</p>    <p style="text-align:center"><img alt="Andoird优化,内存优化" src="https://simg.open-open.com/show/bd9d25cd59af06daa7a0b9571b9000c8.png"></p>    <h2>题记</h2>    <blockquote>     <p>应用的生存期绝大部分时间都用于处理内存中的数据,虽然我们大多数人都意识到在手机上要尽可能少使用内存,但并非所有人都认识到了内存使用对性能的影响。所以,下面我们来讨论一下。</p>    </blockquote>    <h2><strong>一、谈谈移动设备中的内存</strong></h2>    <blockquote>     <ul>      <li> <p>无论分配给应用多少内存,它都不会满足。</p> </li>      <li> <p>移动设备和传统的电脑有两个很大的差异;</p>       <ul>        <li>物理内存大小</li>        <li>虚拟内存交换能力</li>       </ul> </li>      <li> <p>要在一定设备上使用尽可能少的内存,既是经验也是常识。</p>       <ul>        <li>好处:<br> 减少碰到oom异常的风险<br> 提升性能</li>       </ul> </li>      <li> <p>性能取决于以下三个因素( 我们会在下面讲解)</p>       <ul>        <li>CPU如何操纵特定的数据类型</li>        <li>数据和指令需要占用多少存储空间</li>       </ul> </li>     </ul>    </blockquote>    <h2><strong>二、采用合适的数据类型</strong></h2>    <blockquote>     <p>使用long比short和int慢<br> 同样,只使用double及混用float和double,比只用float慢。</p>     <p>注意:由于并不是所有指令的执行时间都相同,再加上cpu很复杂,所以并不能推测出具体的时间。 short数组排序远比其他类型数组快</p>     <pre>  <code class="language-java">原因: short使用计数排序,算法复杂度是线性的       而int和long使用快速排序算法</code></pre>     <p>处理64位类型(long或double)比处理32位类型慢</p>    </blockquote>    <p>总的来说,<br> 就是:</p>    <blockquote>     <p>1、处理大量数据时,使用可以满足要求的最小数据类型</p>     <p>2、避免类型转换。尽量保持类型一致,尽可能在计算中使用单一类型。</p>     <p>3、如果有必要取得更好的性能,推倒重来,但要认真处理。</p>    </blockquote>    <h2><strong>三、你需要知道的访问内存</strong></h2>    <blockquote>     <p>1、操纵较大类型的数据代价较高,因为用到了指令较多。 直观的来说,指令越多性能越差,CPU需要做很多额外的工作</p>     <p>2、此外、代码和数据都驻留在内存中,访问内存本身也有开销。 因为访问内存会产生一些开销,CPU会把最近访问的内容缓存起来,无论是内存读还是写。</p>     <p>3、CPU通常使用两级缓存或者三级缓存:</p>     <ul>      <li>一级缓存</li>      <li>二级缓存</li>      <li>三级缓存(一般用于服务器机或游戏机器)</li>     </ul>     <p>4、当数据或指令在缓存中找不到时,就是缓存未命中。这是需要从内存中读取数据或指令。<br> 缓存未命中几种情况:</p>     <ul>      <li>指令缓存读未命中</li>      <li>数据缓存读未命中</li>      <li>写未命中</li>     </ul>     <p>注意:第一种缓存未命中最关键,因为CPU要一直等到从内存中读出指令,才可以继续执行。</p>     <p>另外:<strong>现代CPU都能够自动预取内存,为了避免或者只说是限制了缓存未命中情况的发生。</strong></p>    </blockquote>    <h2><strong>四、通过垃圾收集管理内存</strong></h2>    <blockquote>     <p>1、Java的一个非常重要的优点是垃圾收集</p>     <ul>      <li>原理: 不再使用的对象内存会被垃圾收集器释放(回收)。</li>      <li>注意:还是会出现内存泄露的情况。</li>      <li>垃圾收集器会帮你管理内存,它做的不仅仅是释放不用的内存。</li>     </ul>     <p>2、内存泄漏:</p>     <ul>      <li>只有当某个对象不再被引用时,它的内存才会被回收,当该被释放的对象引用仍然存在时就会发生内存泄漏。</li>      <li>一个典型例子就是,由于屏幕旋转,整个Activity对象会有泄露 很严重!因为Activity对象占用相当多内存。</li>     </ul>     <p>3、 避免内存泄漏方案。(大多数只能用来分析,并不会告诉你是否内存泄漏)</p>     <ul>      <li>DDMS视图里面的Heap与Tracker 可以跟踪内存使用和分配情况。 AS里面的monitor 有内存、网络、等四个视图</li>      <li>StrictMode类 会将检测到的违规操作,将结果写到日志中。 只能用来分析,并不会告诉你是否内存泄漏</li>      <li>OneAPM 用过,并且也去面试过,很不错。</li>     </ul>    </blockquote>    <h2><strong>五、通过Java中的引用来更好的管理</strong></h2>    <blockquote>     <p>1、内存释放是垃圾收集器的一个重要的特性,在垃圾收集器中它的作用比在内存管理系统中大得多。</p>     <p>2、Java定义了4中类型的引用</p>     <ul>      <li>强(Strong): <pre>  <code class="language-java">  其实就是普通的创建对象,保持无用对象的强引用可能会导致内存泄漏</code></pre> </li>      <li>软(Soft): <pre>  <code class="language-java">  其实软引用和弱引用在本质上是类似的,软引用适用于缓存,它可以自动删除缓存中的条目</code></pre> </li>      <li>弱(Weak) <pre>  <code class="language-java">    保障下次垃圾回收时基本会收走</code></pre> </li>      <li>虚(Phantom) <pre>  <code class="language-java">       几乎很少用到</code></pre> </li>     </ul>     <p>3、当需要缓存或映射时,你不必实现类似的内存管理系统。精心规划引用后,大部分工作可以放心地交给垃圾收集器完成。</p>     <p>4、 垃圾收集<br> 垃圾收集可能会再不定的时间触发,你几乎无法控制它的时机。<br> 但是有时,你可以通过System.gc( );提醒一下Android,<br> 虽然如此,垃圾收集机制发生时间最终时间是不由你确定的。</p>     <p>5、 垃圾收集发生在应用的主线程,所以:</p>     <ul>      <li>很可能降低响应速度和性能。</li>      <li>在及时游戏中会出现丢帧,因为有太多时间花在垃圾收集上。</li>      <li>Andorid2.3有了转机,垃圾收集工作转移到了一个单独的线程。比以前的Android版本好太多了</li>     </ul>    </blockquote>    <h2><strong>六、通过系统的API可以了解、管理内存</strong></h2>    <blockquote>     <p>1、 Android定义了几个API,你可以用他们来了解系统中还剩多少可用内存和用了多少内存</p>     <ul>      <li> <p>ActivityManager的:</p> <pre>  <code class="language-java"> getMomoryInfo()        getMomoryClass()        getLargeMeoryClass()</code></pre> </li>      <li> <p>Debug的</p> <pre>  <code class="language-java"> dumpHprofData()  getNativeHeapAllocatedSize()  getNativeHeapSize()</code></pre> </li>     </ul>     <p>提示:<br> <strong>在应用的manifest文件中把android:largeHeap设为true,就可以让应用使用更大的堆。</strong></p>    </blockquote>    <h2><strong>七、当内存少的时候可以这样处理</strong></h2>    <blockquote>     <p>ComponentCallbacks接口定义了API <strong>onLowMomory( ),</strong>它对所有应用组> 件都是相同的。当它被调用时,组件基本会被要求释放那些并不会用到的内存。<br> 可以被释放的内容:</p>     <ul>      <li>缓存或缓存条目(如使用强引用的LruCache)</li>      <li>可以再次按需生成的位图对象</li>      <li>不可见的布局对象</li>      <li>数据库对象</li>     </ul>    </blockquote>    <h2><strong>八、通过5R法来对ANDROID内存进行优化:</strong></h2>    <h3><strong>1.Reckon</strong>(计算)</h3>    <blockquote>     <p>首先需要知道你的app所消耗内存的情况,知己知彼才能百战不殆<br> 通过上文提到的工具进行查看消耗,这里再给大家推荐一个工具<br> <strong>Memory Analysis Tool</strong>(MAT):<br> 可以转换成饼图和表格,直观、好用。</p>    </blockquote>    <h3><strong>2.Reduce</strong>(减少)</h3>    <p>Reduce的意思就是减少,直接减少内存的使用是<strong>最有效</strong>的优化方式。</p>    <blockquote>     <p>例如:<br> Bitmap:</p>     <p>Bitmap是内存消耗大户,绝大多数的OOM崩溃都是在操作Bitmap时产生的,下面来看看几个处理图片的方法:</p>    </blockquote>    <p><strong>图片显示:</strong></p>    <blockquote>     <p>例如在列表中仅用于预览时加载缩略图(thumbnails )。</p>     <p>只有当用户点击具体条目想看详细信息的时候,这时另启动一个fragment/activity/对话框等等,去显示整个图片</p>    </blockquote>    <p><strong>图片大小:</strong></p>    <blockquote>     <p>使用BitmapFactory.Options设置inSampleSize, 这样做可以减少对系统资源的要求。</p>    </blockquote>    <pre>  <code class="language-java">BitmapFactory.Options bitmapFactoryOptions = new BitmapFactory.Options();     bitmapFactoryOptions.inJustDecodeBounds = true;     bitmapFactoryOptions.inSampleSize = 2;     // 这里一定要将其设置回false,因为之前我们将其设置成了true       // 设置inJustDecodeBounds为true后,decodeFile并不分配空间,即,BitmapFactory解码出来的Bitmap为Null,但可计算出原始图片的长度和宽度       options.inJustDecodeBounds = false;     Bitmap bmp = BitmapFactory.decodeFile(sourceBitmap, options);</code></pre>    <p><strong>图片像素</strong>:</p>    <blockquote>     <p>Android中图片有四种属性,分别是:<br> ALPHA_8:每个像素占用1byte内存<br> ARGB_4444:每个像素占用2byte内存<br> ARGB_8888:每个像素占用4byte内存 (默认)<br> RGB_565:每个像素占用2byte内存</p>     <p>Android默认的颜色模式为ARGB_8888,这个颜色模式色彩最细腻,显示质量最高。但同样的,占用的内存也最大。 所以在对图片效果不是特别高的情况下使用RGB_565(565没有透明度属性),如下:</p>    </blockquote>    <pre>  <code class="language-java">public static BitmapreadBitMap(Contextcontext, intresId) {         BitmapFactory.Optionsopt = newBitmapFactory.Options();         opt.inPreferredConfig = Bitmap.Config.RGB_565;         opt.inPurgeable = true;         opt.inInputShareable = true;         //获取资源图片          InputStream is = context.getResources().openRawResource(resId);         return BitmapFactory.decodeStream(is, null, opt);     }</code></pre>    <blockquote>     <p><strong>图片回收</strong>:<br> 使用Bitmap过后,就需要及时的调用Bitmap.recycle()方法来释放Bitmap占用的内存空间,而不要等Android系统来进行释放。</p>    </blockquote>    <pre>  <code class="language-java">bitmap.recycle();      bitmap = null;</code></pre>    <p>捕获异常:</p>    <pre>  <code class="language-java">Bitmap bitmap = null;     try {        // 实例化Bitmap        bitmap = BitmapFactory.decodeFile(path);     } catch (OutOfMemoryError e) {         // 捕获OutOfMemoryError,避免直接崩溃    }     if (bitmap == null) {         // 如果实例化失败 返回默认的Bitmap对象         return defaultBitmapMap;     }</code></pre>    <p><strong>修改引用</strong>:</p>    <blockquote>     <p>如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。</p>     <p>另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。</p>    </blockquote>    <h3><strong>3.Reuse</strong>(重用)</h3>    <blockquote>     <p>核心思路就是将已经存在的内存资源重新使用而避免去创建新的,最典型的使用就是缓存(Cache)和池(Pool)。</p>    </blockquote>    <h3><strong>4.Recycle</strong>(回收)</h3>    <blockquote>     <p>Thread(线程)回收:</p>    </blockquote>    <pre>  <code class="language-java">Thread t = new Thread() {         public void run() {             while (true) {                 try {                     Thread.sleep(1000);                     System.out.println("thread is running...");                 } catch (InterruptedException e) {                   }            }         }     };     t.start();     t = null;     System.gc();</code></pre>    <blockquote>     <p>Cursor(游标)回收:</p>    </blockquote>    <pre>  <code class="language-java">@Override      protected void onDestroy() {                 if (mAdapter != null && mAdapter.getCurosr() != null) {               mAdapter.getCursor().close();          }           super.onDestroy();        }</code></pre>    <blockquote>     <p>还有接收器、流等等。</p>     <p><strong>5.Review</strong>(检查)</p>    </blockquote>    <p><strong>Code Review</strong>(代码检查):</p>    <blockquote>     <p>Code Review主要检查代码中存在的一些不合理或可以改进优化的地方,</p>    </blockquote>    <p><strong>UI Review</strong>(视图检查):</p>    <blockquote>     <p>Android对于视图中控件的布局渲染等会消耗很多的资源和内存,所以这部分也是我们需要注意的。<br> 减少视图层级:<br> 减少视图层级可以有效的减少内存消耗,因为视图是一个树形结构,每次刷新和渲染都会遍历一次。</p>     <p><strong>hierarchyviewer</strong>:</p>     <p>想要减少视图层级首先就需要知道视图层级,所以下面介绍一个SDK中自带的一个非常好用的工具hierarchyviewer。</p>     <p>你可以在下面的地址找到它:your sdk path\sdk\tools</p>    </blockquote>    <h2><strong>总结</strong></h2>    <blockquote>     <p>删除对象应该仔细考虑,因为重新创建是需要开销的。</p>     <p><strong>如果没有释放出足够的内存可能会导致Android系统更激进的行为(如杀死进程)。</strong></p>     <p>如果应用进程被杀掉了,用户下次使用又要从头开始。因此,<strong>应用不仅要表现出色,也要释放尽可能多的资源</strong>。 代码中推迟初始化是一个好的方式。</p>     <p>内存在嵌入式设备上是稀缺资源。尽管今天的手机和平板电脑的内存越来越多, 但这些设备也在运行越来越复杂的系统和应用。有效的使用内存, 不仅可以使应用在旧设备上运行时占用较少的内存, 还可以让程序跑的更快。请记住,<strong>应用对内存的需求是无止境的。</strong></p>    </blockquote>    <p>Anroid优化(二)_内存优化.xmind 下载:<a href="/misc/goto?guid=4959675806508501094">http://pan.baidu.com/s/1hsK2Co0</a> 密码:abcs</p>    <p><br>  </p>    <p>来自:http://www.jianshu.com/p/afd4d8a6dcd6</p>