内存

 
JAVA是在JVM所虚拟出的内存环境中运行的,内存分为三个区:堆、栈和方法区。
栈(stack):是简单的数据结构,程序运行时系统自动分配,使用完毕后自动释放。优点:速度快。
堆(heap):用于存放由new创建的对象和数组。在堆中分配的内存,一方面由java虚拟机自动垃圾回收器来管理,另一方面还需要程序员提供修养,防止内存泄露问题。
方法区(method):又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
 

Java GC

 

GC可以自动清理堆中不在使用(不在有对象持有该对象的引用)的对象。

在JAVA中对象如果再没有引用指向该对象,那么该对象就无从处理或调用该对象,这样的对象称为不可到达(unreachable)。垃圾回收用于释放不可到达的对象所占据的内存。

对android来说,内存使用尤为吃紧,最开始的app进程最大分配才8M的内存,渐渐增加到16M、32M、64M,但是和服务端相比还是很渺小的。如果对象回收不及时,很容易出现OOM错误。

内存泄露

 
什么是内存泄露?程序通过new分配内存,在使用完毕后没有释放,造成内存占用。这块内存不受GC控制,无法通过GC回收。
主要表现在:当一个对象已经不再使用,本该被回收的,但是另外一个正在使用的对象持有它的引用从而就导致对象不能被回收。这种对象存在堆内存中,就产生了内存泄漏。
 

危害?内存泄漏对于app没有直接的危害,即使app有发生内存泄漏的情况,也不一定会引起app崩溃,但是会增加app内存的占用。内存得不到释放,慢慢的会造成app内存溢出。解决内存泄漏目的就是防止app发生内存溢出。

 
内存泄露主要表现的当Activity在finish的时候,由于对象持有对Activity的引用,造成Activity没有被及时回收。总结了下大致有5种情况造成内存泄露,(1)static变量、匿名类的使用 (2)线程执行处理(3)各种监听回调处置(4)Bitmap等回收处置(5)集合类只有增操作却没有减操作。
 
常见情况
1)外部类持有Activity的静态引用
  1. public class MainActivity extends AppCompatActivity {
  2. static Activity activity;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. CommUtil commUtil = CommUtil.getInstance(this);
  8. }
  1. public class CommUtils {
  2. private static CommUtils instance;
  3. private Context context;
  4. private CommUtils(Context context) {
  5. this.context = context;
  6. }
  7. public static CommUtils getInstance(Context context) {
  8. if (instance == null) {
  9. instance = new CommUtils(context);
  10. }
  11. return instance;
  12. }
  13. }

2)异步执行耗时任务期间时,Thread、AsyncTask、TimeTask持有的Activty进行finish时,Activity实例不会被回收。

  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. setContentView(R.layout.activity_main);
  4. new AsyncTask<String, Void, String>() {
  5. @Override
  6. protected String doInBackground(String... params) {
  7. for (int i = 0; i < 15; i++) {
  8. try {
  9. Log.e("MainActivity2", "dddd" + i + MainActivity2.this.getLocalClassName());
  10. Thread.sleep(1000);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. return null;
  16. }
  17. @Override
  18. protected void onPostExecute(String s) {
  19. super.onPostExecute(s);
  20. }
  21. }.execute();
  22. }

3)Handler内部类造成内存泄露。

Handler为非静态内部类时会隐式持有当前activity引用。当Activity被 finish()时,若Handler有未处理完或延迟的消息(主要是Handler牵扯到线程问题),会造成activity不能被回收。
  1. MyHandler myHandler = new MyHandler();
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. myHandler.postDelayed(new Runnable() {
  6. @Override
  7. public void run() {
  8. }
  9. }, 50 * 1000);
  10. }
  11. class MyHandler extends Handler {
  12. @Override
  13. public void handleMessage(Message msg) {
  14. super.handleMessage(msg);
  15. }
  16. }

解决办法:在Activity生命周期结束前,确保Handler移除消息(mMyHanlder.removeCallbacksAndMessages(null);)或者使用静态Handler内部类。

如:使用了弱引用替代强引用.
  1. static MyHandler myHandler;
  2. @Override
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. myHandler = new MyHandler(this);
  6. }
  7. static class MyHandler extends Handler {
  8. WeakReference<Activity> mActivityReference;
  9. MyHandler(Activity activity) {
  10. mActivityReference = new WeakReference<Activity>(activity);
  11. }
  12. @Override
  13. public void handleMessage(Message msg) {
  14. final Activity activity = mActivityReference.get();
  15. if (activity != null) {
  16. //....
  17. }
  18. }
  19. }
建议熟悉下:强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)
 
4)匿名内部类的使用。
  1. public class DemoActivity extends AppCompatActivity {
  2. Runnable runnable = new Runnable() {
  3. @Override
  4. public void run() {
  5. }
  6. };

runnable默认会持有DemoActivity的引用。若Activity被finish的时候,如线程在使用runnable,则会造成内存泄露。

 
5)构造Adapter时没有使用缓存的 convertView
 
  1. public View getView(int position, View convertView, ViewGroup parent) {
  2. View view = null;
  3. if (convertView == null)
  4. convertView = View.inflate(this, R.layout.item_layout, false);
  5. view = convertView;
  6. return view;
  7. }
6) 当使用了BraodcastReceiver、Cursor、Bitmap等资源时,若没有及时释放,则会引起内存泄漏。
7)集合类的不当使用。
 

更多内存泄露可以通过检测工具发现。检测工具主要有MAT、Memory Monitor 、Allocation Tracker 、Heap Viewer、LeakCanary

内存溢出

什么是内存溢出?out of memory。 程序向系统申请的内存空间超出了系统能给的。内存泄露很容易引起OOM。
 

内存抖动

内存抖动是指在短时间内有大量的对象被创建或者被回收的现象,主要是循环中大量创建、回收对象。这种情况应当尽量避免。
 
 
 

Android之内存泄露、内存溢出、内存抖动分析的更多相关文章

  1. 【转】Java学习---内存泄露与溢出的区别

    Java内存泄露与溢出的区别 Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽): 而Java内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于 ...

  2. 牛客网Java刷题知识点之内存溢出和内存泄漏的概念、区别、内存泄露产生原因、内存溢出产生原因、内存泄露解决方案、内存溢出解决方案

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

  3. JavaScript内存泄露,闭包内存泄露如何解决

    本文原链接:https://cloud.tencent.com/developer/article/1340979 JavaScript 内存泄露的4种方式及如何避免 简介 什么是内存泄露? Java ...

  4. Java 基础 - 内存泄露Memory leak & 内存溢出Out of memory

    内存泄露 & 内存溢出 关系 https://www.cnblogs.com/panxuejun/p/5883044.html 内存泄露的6种情况: https://blog.csdn.net ...

  5. (转)IE内存泄露,iframe内存泄露造成的原因和解决方案

    http://my.oschina.net/jsan/blog/11169 http://blog.csdn.net/tianma630/article/details/8502395 jQuery ...

  6. [转]深入Android内存泄露

    深入内存泄露 Android应用的内存泄露,其实就是java虚拟机的堆内存泄漏. 当然,当应用有ndk,jni时,没有及时free,本地堆也会出现内存泄漏. 本文只是针对JVM内存泄漏应用,进行阐述分 ...

  7. Android 性能优化之使用MAT分析内存泄露问题

    我们平常在开发Android应用程序的时候,稍有不慎就有可能产生OOM,虽然JAVA有垃圾回收机,但也不能杜绝内存泄露,内存溢出等问题,随着科技的进步,移动设备的内存也越来越大了,但由于Android ...

  8. Android性能优化:手把手带你全面了解 内存泄露 & 解决方案

    . 简介 即 ML (Memory Leak)指 程序在申请内存后,当该内存不需再使用 但 却无法被释放 & 归还给 程序的现象2. 对应用程序的影响 容易使得应用程序发生内存溢出,即 OOM ...

  9. Android 性能优化之使用MAT分析内存泄露

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/42396507),请尊重他人的辛勤劳动成果,谢谢! 我们平常 ...

随机推荐

  1. Windows 环境 cygwin 安装 SSH

    本文内容 安装环境 安装 cygwin 安装 SSH 服务 启动 sshd 服务 SSH 免密码登录 验证 SSH 是否已安装成功 验证 SSH 是否可以免密码登录本机 安装环境 Windows 20 ...

  2. android中RecyclerView控件的列表项横向排列

    本文是在上一篇文章的基础上做的修改:android中RecyclerView控件的使用 1.修改列表项news_item.xml:我这里是把新闻标题挪到了新闻图片的下面显示 <?xml vers ...

  3. WCF服务引用之后自动生成的泛型代理类名称太长的解决方案

    问题:WCF服务引用之后会将原来的泛型类自动生成一个代理类,但是有时候名称太长怎么办? 解决方案: 1.方案一: 调用客户端同样也引用这个泛型类的类库. 2.方案二: 找到这个泛型类,然后在上面的[D ...

  4. SQL中Union和UnionAll的使用

    SQL中Union和UnionAll的使用 1.建立一个Student表 ,如下: 2.建立一个Teacher表,如下: 3.使用Union,将去重并组合表,效果: 4.使用Union All,不去重 ...

  5. Linux内核配置:Makefile目标

    在顶层Linux源码目录中输入命令make help,它会显示一长串从源码树中生成的目标列表.最常见的使用make的方式是不指定目标,在这种情况下,它会生成内核ELF文件vmlinux和针对所选架构的 ...

  6. 【转】跟我一起学Spring 3(4)–深入理解IoC(控制反转)和DI(依赖注入)

    在继续下面的章节之前,我们要先说说大名鼎鼎的IoC和DI. 我们经常会听说IoC,也就是Inversion of Controller,控制反转.事实上,IoC并不是一个新鲜的概念,最早可能是在198 ...

  7. 【Python】文件读写操作

    Python的文件读写有点类似php的文件读写.php的文件读写已经在<[php]让记事本成为你调控变量的控制台>(点击打开链接)说过了,以下用一个小样例说明Python的文件读写. 在F ...

  8. JavaWeb应用出现HTTP 500-Unable to compile class for JSP 错误 的解决

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6383192.html 在上一篇博文中,我们把自己本机的web项目部署到了云主机的tomcat上.之后通过浏览器 ...

  9. Fiddler Web Debugger简单调试头部参数

    POST接口时头部参数如下: User-Agent: Fiddler Host: api.***.com Content-Length: Content-Type: application/json ...

  10. Eureka客户端网卡和网段选择

    当机器上有多个网卡或者机器上配置了回环地址的时候,Eureka客户端呈报给服务端的IP将不可预见,为了指定IP我们需要增加以下配置: 在bootstrap.yml中增加配置内容: spring: cl ...