zoukankan      html  css  js  c++  java
  • 内存优化

    Android的内存机制

    Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似。程序员通过new为对象分配内存,所有对象在java堆内分配空间;然而对象的释放是由垃圾回收器来完成的。C/C++中的内存机制是“谁污染,谁治理”,java的就比较人性化了,给我们请了一个专门的清洁工(GC)。

    那么GC怎么能够确认某一个对象是不是已经被废弃了呢?Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。 线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。

    Android的内存溢出

    Android的内存溢出是如何发生的?

    Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M,有的机器为24M。因此我们所能利用的内存空间是有限的。如果我们的内存占用超过了一定的水平就会出现OutOfMemory的错误。

    造成内存溢出的原因

    为什么会出现内存不够用的情况呢?我想原因主要有两个:

    长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。

    保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。

    1、线程

    线程是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。

    有些人喜欢用Android提供的AsyncTask,但事实上 AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了 ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为 Activity的内部类,就更容易出现内存泄露的问题。

    事实上,线程的问题并不仅仅在于内存泄露,还会带来一些灾难性的问题 。

    2、Context

    长期保持某些资源(如Context)的引用,如将Context的引用传给一个静态的对象

    private static Drawable sBackground;  
    
    
    @Override  
    
    protected void onCreate(Bundle state) {  
    
      super.onCreate(state);  
    
      TextView label = new TextView(this);  
    
      label.setText("Leaks are bad");  
    
      if (sBackground == null) {  
    
        sBackground = getDrawable(R.drawable.large_bitmap);  
    
      }  
    
      label.setBackgroundDrawable(sBackground);  
    
      setContentView(label);  
    
    }

    sBackground是一个静态的变量,但是我们发现,我们并没有显式的保存Contex的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用。这个引用链如下:
    Drawable->TextView->Context,所以,最终该Context也没有得到释放,发生了内存泄露。
    如何才能有效的避免这种引用的发生呢?

    应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。

    Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。

    使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;

    3、Adapter

    getView()方法中,如果我们不去使用 缓存的convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。

    所以使用缓存和ViewHolder来减少内存占用。

    4、Bitmap

    Bitmap是内存大户,太多的Bitmap很容易就能将内存爆掉。

    Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null。合理的使用压缩和缓存来减少Bitmap在内存中的数量和大小。

    5、Cursor

    Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。然而如果Cursor的数据量特表大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,会给用户以错误提示。

    有一种情况下,我们不能直接将Cursor关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭。

    6、io流

    在使用文件或者访问网络资源时,使用了InputStream/OutputStream也会导致内存泄露,使用完要及时关闭。

    7、集合

    我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。code中务必及时清理。

  • 相关阅读:
    内部类
    三大修饰符:static、final、abstract
    面向对象三大特性
    类和方法
    Vue-创建工程+element UI
    xshell连接虚拟机较慢问题 -----已解决
    Hbase配置
    Hive的安装配置
    Hive内容+配置
    Redis全局命令
  • 原文地址:https://www.cnblogs.com/allin1579/p/4930935.html
Copyright © 2011-2022 走看看