android内存泄露问题


http://blog.csdn.net/fastthinking/article/details/38898193

1.安卓开发时,如何开发出质量高的代码?如何及时释放内存,不造成内存泄露?

    公共变量不要包含对Activity/Fragment的引用。保证及时的销毁Activity/Fragment的对象。

   参考http://blog.csdn.net/a345017062/article/details/8301398(Activity、Fragment对象内存泄漏的解决思路)

activity contex and memery leak     

   http://blog.csdn.net/prog_dong/article/details/5618995


2.此人遇到的问题应该是内存管理不当。fragment虽然调用了remove。但是其中的变量可能生命周期大于fragment并且引用了fragment。导致无法回收。

点击打开链接


3.如何判断程序是否存在内存泄露?

http://www.360doc.com/content/14/0516/14/9462341_378228520.shtml


4.content、Application、SharePreference与全局变量如何使用?

http://www.360doc.com/content/12/0531/11/7559693_214938173.shtml


5.android静态引用变量的生命周期

http://blog.csdn.net/ctcwri/article/details/8858414


//

http://blog.csdn.net/ctcwri/article/details/8858414

Android是用Java开发,其静态变量的生命周期遵守Java的设计。我们知道静态变量是在类被load的时候分配内存的,并且存在于方法区。当类被卸载的时候,静态变量被销毁。在PC机的客户端程序中,一个类被加载和卸载,可简单的等同于jvm进程的启动和结束。那么在Android中呢?用的Dalvik vm也是一样的。不过Android不太突出的进程概念,所以对静态变量的生命周期就会感觉模糊,这种模糊对于值类型是无所谓的,如果是静态的对象引用,则与内存回收、内存泄漏这些问题有关,有必要加深研究和理解。

一、静态变量在类被加载的时候分配内存。

类在什么时候被加载?

当我们启动一个app的时候,系统会创建一个进程,此进程会加载一个Dalvik VM的实例,然后代码就运行在DVM之上,类的加载和卸载,垃圾回收等事情都由DVM负责。也就是说在进程启动的时候,类被加载,静态变量被分配内存。

二、静态变量在类被卸载的时候销毁。

类在什么时候被卸载?

在进程结束的时候。

说明:一般情况下,所有的类都是默认的ClassLoader加载的,只要ClassLoader存在,类就不会被卸载,而默认的ClassLoader生命周期是与进程一致的,本文讨论一般情况。

三、Android中的进程什么时候结束

这个是Android对进程和内存管理不同于PC的核心——如果资源足够,Android不会杀掉任何进程,另一个意思就是进程随时可能会被杀掉。而Android会在资源够的时候,重启被杀掉的进程。也就是说静态变量的值,如果不做处理,是不可靠的,可以说内存中的一切都不可靠。如果要可靠,还是得保存到Nand或SD卡中去,在重启的时候恢复回来。

另一种情况就是不能把退出所有Activity等同于进程的退出,所以在用户点击图标启动应用的时候,以前存放于静态变量中的值,有可能还存在,因此要视具体情况给予清空操作。

四、Application也是一样不可靠

Application其实是一个单例对象,也是放在内存中的,当进程被杀掉,就全清空了,只不过Android系统会帮重建Application,而我们存放在Application的数据自然就没有了,还是得自己处理。

五、静态引用的对象不会被垃圾回收

只要静态变量没有被销毁也没有置null,其对象一直被保持引用,也即引用计数不可能是0,因此不会被垃圾回收。因此,单例对象在运行时不会被回收。

//

http://blog.csdn.net/u013233097/article/details/50313993

Android中内存泄露的原因分析:

有垃圾回收机制,为什么还会出现内存泄露:

了解GC回收的原理:

           GC会选择一些它了解还存活的对象作为内存遍历的根节点(GC Roots),比方说thread stack中的变量,JNI中的全局变量,zygote中的对象(class loader加载)等,然后开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。


1,内存泄露和内存溢出:

 内存泄露:

               内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
      Android主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的。如果我们编写的代 码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机。为了能够使得Android应用程序安全且快速的运行,Android 的每个应用程序都会使用一个专有的Dalvik虚拟机实例来运行,它是由Zygote服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运 行的。一方面,如果程序在运行过程中出现了内存泄漏的问题,仅仅会使得自己的进程被kill掉,而不会影响其他进程(如果是system_process 等系统进程出问题的话,则会引起系统重启)。另一方面Android为不同类型的进程分配了不同的内存使用上限,如果应用进程使用的内存超过了这个上限, 则会被系统视为内存泄漏,从而被kill掉

          Java内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到gc roots导致无法被GC回收。无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏。


内存溢出:

            内存溢出(out of memory)通俗理解就是内存不够,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。此时软件或游戏就运行不了,系统会提示内存溢出,有时候会自动关闭软件。

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

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

  • 由于我们程序的失误,长期保持某些资源(如Context)的引用,造成内存泄露,资源造成得不到释放。
  • 保存了多个耗用内存过大的对象(如Bitmap),造成内存超出限制。

区别:


内存泄露memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存迟早会被占

光。   是指向系统中申请分配内存进行使用(new),但使用完后,却没有归还。申请到的内存自己也不能再访问,而系统也不能再次将它分配给需要的程序。

内存溢出out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of  memory;比如申请了一个integer,但给他存了long才能存下的数。

比如栈:栈满时,进行进栈,内存溢出。栈空时,进行出栈,内存也会溢出。分配内存不足以放下数据项序列,称为内存溢出。

内存泄露会导致内存溢出。


2,导致内存泄露的原因分析 :


          1,静态变量导致的内存泄露:


[java]  view plain  copy
  1. public  class MainActivity extends Activity{  
  2.   
  3.           private static final String TAG = "MainActivity";  
  4.           private static Context sContext;  
  5.   
  6.   
  7.           @Override  
  8.           protected void onCreate(Bundle savedInstanceState){  
  9.                   super.onCreate(savedInstanceState);                   
  10.                    
  11.                   setContentView(R,layout.main);                    
  12.                   sContext = this;//sContext为静态变量,生命周期较长。导致当前activity无法销毁,因次静态sContext引用了它。导致内存泄露。  
  13.      }  
  14.  }  
  15. //由于用静态成员 TAG 缓存了drawable对象,所以activity加载速度会加快,但是这样做是错误的。  
  16. //因为在android 2.3系统上,它会导致activity销毁后无法被系统回收。  

            2,单例模式导致的内存泄露:

[java]  view plain  copy
  1.     import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class TestClass {  
  5.       
  6.     //创建     变量  
  7.     private List<OnDataArrivedListener> mOnDataArrivedListeners = new ArrayList<OnDataArrivedListener>();  
  8.       
  9.     //创建类  
  10.     private static class SingleHolder{  
  11.         public static final TestClass INSTANCE = new TestClass();  
  12.     }  
  13.       
  14.     //构造参数:  
  15.     private TestClass(){}  
  16.       
  17.     //单例模式:  
  18.     public static TestClass getInstance(){  
  19.         return SingleHolder.INSTANCE;  //调用帮助类的     常量  
  20.     }  
  21.       
  22.     //添加同步:  
  23.     public synchronized void registerListener(OnDataArrivedListener listener){  
  24.           
  25.         if(!mOnDataArrivedListeners.contains(listener)){  
  26.             mOnDataArrivedListeners.add(listener);  
  27.         }  
  28.     }  
  29.       
  30.     //取消注册监听方法  
  31.     public synchronized void unregisterListener(OnDataArrivedListener listener){  
  32.         mOnDataArrivedListeners.remove(listener);  
  33.     }  
  34.       
  35.     //定义数据接口:  
  36.     public interface OnDataArrivedListener{  
  37.         //定义方法  
  38.         public void onDataArrived(Object obj);  
  39.     }  
  40.       
  41. }  

调用上面的代码:


[java]  view plain  copy
  1.       
  2. protected void on Create(Bundle savedInstance){  
  3.      
  4.       supper.onCreate(savedInstanced);  
  5.   
  6.       setContentView(R.layout.main);  
  7.   
  8.       TestClass.getInstance().registerListener(this);//activity实现onDataArrivedListener接口,并向TestClass注册监听。  
  9. //单例模式     的生命周期和Application保持一直,因此Activity对象无法被即时的释放。导致内存泄露。  
  10.   
  11.   
  12. }  
  13.   
  14.     

3,属性动画导致的内存泄露:


             属性动画中有一类无线循环的动画,如果在Activity中播放此类动画而且没有在onDestory中去 停止动画。那么动画会一直播放下去,尽管已经看不到动画效果了。并且这个时候Activity的View会被动画持有。而View又持有了Activity无法释放。下面动画是无线循环,会泄露当前的Activity,解决办法是在Activity的onDestory中调用animator.cancel();

[java]  view plain  copy
  1. animator.cancel();  


4.Bitmap使用不当造成内存泄露:

        当我们使用Bitmap对象开辟对象时,较大的Bitmap对象会被创建,其占用内存过多,超出堆的上限时,便会抛出内存泄露的危险。Bitmap对象不在使用时调用recycle()释放内存时会造成内存泄露。如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

        第一、及时的销毁,解决方案。

       虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过Java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。


[java]  view plain  copy
  1.     
  2. //采样率方法一,简单设置为2:  
  3. BitmapFactory.Options newOpts= new BitmapFactory.Options();   
  4. newOpts.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一   
  5. Bitmap bitmap =BitmapFactory.decodeFile(srcImgPath, newOpts);  
  6.   
  7. //采样率方法二,循环原来的二倍:  
  8. Bitmap bm=null;  
  9. BitmapFactory.Options newOpts = new BitmapFactory.Options();  
  10. while(bm==null)  
  11. {  
  12.       try {  
  13.                  bm = BitmapFactory.decodeFile(srcImgPath, newOpts);  
  14.                  break;  
  15.           catch (OutOfMemoryError e)  
  16.           {  
  17.                 e.printStackTrace();  
  18.           }  
  19.           newOpts.inSampleSize*=2;  
  20. }  
  21.   
  22. //采样率方法三,循环直到不会抛出OutOfMemoryError:  
  23. Bitmap bm=null;  
  24. BitmapFactory.Options newOpts = new BitmapFactory.Options();  
  25. while(bm==null)  
  26. {  
  27.          try {  
  28.                  bm = BitmapFactory.decodeFile(srcImgPath, newOpts);  
  29.                   break;  
  30.                 catch (OutOfMemoryError e)  
  31.                {  
  32.                         e.printStackTrace();  
  33.                }  
  34.                       
  35.               newOpts.inSampleSize++;  
  36.  }  
  37.   
  38. //采样率方法四,根据图片文件大小阀值,比如100K:  
  39. newOpts.inSampleSize=(int) Math.ceil(Math.sqrt(fileLength/100*1024));  
  40.   
  41. //采样率方法五,根据图片文件宽度和高度  
  42. int standardImgWidth=640;  
  43. int standardImgHeight=640;  
  44. int widthRation=width/standardImgWidth;  
  45. int heightRation=height/standardImgHeight;  
  46. newOpts.inSampleSize=(widthRation>heightRation)?heightRation:widthRation;  
  47.   
  48. //采样率方法六,根据图片文件大小阀值/图片文件宽度和高度  
  49. rationSize=方法四获取的inSampleSize;  
  50. rationDimens=方法五获取的inSampleSize;  
  51. newOpts.inSampleSize=Math.min(rationSize, rationDimens);  

5,handler造成的内存泄露:

            handler:Handler持有对UI主线程消息队列MessageQueue和循环Looper的引用。子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。UI主线程通过Looper循环查询消息队列的UI_MQ,当发现有消息存在时会将消息从队列中取出。首先分析消息,通过消息的参数判断该消息对应的Handler,然后将消息分发到指定的Handler进行处理。


[java]  view plain  copy
  1. public class SampleActivity extends Activity {  
  2.   
  3.   private final Handler mHandler = new Handler() {  
  4.     @Override  
  5.     public void handleMessage(Message msg) {  
  6.       // ...  
  7.     }  
  8.   }  
  9.   
  10.   @Override  
  11.   protected void onCreate(Bundle savedInstanceState) {  
  12.     super.onCreate(savedInstanceState);  
  13.   
  14.     // 发送一个10分钟后执行的一个消息  
  15.     mHandler.postDelayed(new Runnable() {  
  16.       @Override  
  17.       public void run() { }  
  18.     }, 600000);  
  19.   
  20.     // 结束当前的Activity  
  21.     finish();  
  22.   }  
  23.   
  24. //当Activity结束后,在 Message queue 处理这个Message之前,它会持续存活着。这个Message持  
  25.   
  26. //有Handler的引用,而Handler有持有Activity(SampleActivity)的引用,这个Activity所有的资  
  27.   
  28. //源,在这个消息处理之前都不能也不会被回收,所以发生了内存泄露。  
  29.   
  30.  }  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值