内存优化,性能优化

内存溢出

1,大量使用静态变量

2,大量的递归或无限递归(递归中用到了大量的建新的对象)

3,大量循环或死循环(循环中用到了大量的新建的对象)

4,检查App中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。

5,检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。

6,检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行”+”就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。


1. 资源释放问题 
程序代码的问题,长期保持某些资源,如Context、Cursor、IO流的引用,资源得不到释放 
造成内存泄露。 
2. 对象内存过大问题 
保存了多个耗用内存过大的对象(如Bitmap、XML文件),造成内存超出限制。 
3.static 关键字的使用问题 
static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是 
该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费 
过多的实例(Context的情况最多),这时就要谨慎对待了。 


1、图片过大导致OOM 

3.查询数据库中有没有关闭游标 
我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会出现内 
存问题,这样就会给以后的测试和问题排查带来困难和风险。

4、构造Adapter时,没有使用缓存的 convertView 
在使用ListView的时候通常会使用Adapter,那么我们应该尽可能的使用ConvertView。 
为什么要使用convertView? 
当convertView为空时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。 
当 convertView 不为空,重复利用已经创建的 view 的时候,使用 getTag()方法获取绑定的 
ViewHolder对象,这样就避免了findViewById对控件的层层查询,而是快速定位到控件。 
5、Bitmap对象不再使用时调用recycle()释放内存 
有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不再被使用的时 
候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。 
6、其他 
Android 应用程序中最典型的需要注意释放资源的情况是在 Activity 的生命周期中,在onPause()、onStop()、 onDestroy()方法中需要适当的释放资源的情况。使用广播没有注销也会产生OOM。

2. Android内存泄漏发生的情况

内存泄漏是否发生的关键在于对象之间生命周期的长短。下面是可能发生内存泄漏的情况:

    • 单例模式:内部实现是静态变量和方法
    • 静态的View:view默认持有Activity的context
    • 静态Activity
    • 监听器:当使用Activity的context注册监听,不再需要监听时没有取消注册。比如传感器的监听等
  • 匿名内部类:持有外部类引用。匿名内部类和异步任务一起出现时,可能发生内存泄漏。Activity回收时,异步任务没有执行完毕会导致内存泄漏的发生。因为匿名任务类持有Activity引用,当匿名任务类的引用被另一线程持有,导致生命周期不一致的问题,进而导致内存泄漏

  • 非静态内部类:持有外部类引用

      • Handler:我们知道Handler处理消息是串行的,所以当Activity已经需要回收,但Looper仍有消息未处理完毕时会发生内存泄漏。因为Looper使用ThreadLocal保存,ThreadLocal是静态的,生命周期与当前应用一致。同时Looper持有MessageQueue的引用,MessageQueue持有Handler引用(msg.target),Handler持有外部Activity引用,导致Activity无法回收
      • 非静态内部类有一个静态的实例:非静态内部类持有外部类引用,如果在某个地方有个非静态内部类的静态实例的话,同样会引起内存泄漏
  • 资源对象未关闭:BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源,使用后未关闭会导致内存泄漏。因为资源性对象往往都用了一些缓冲,缓冲不仅存在于 java虚拟机内,还存在于java虚拟机外。如果仅仅是把它的引用置null,而不关闭它们,也会造成内存泄漏

  • 容器中的对象没有清理:集合一般占用内存较大,不及时关闭会导致内存紧张(不会导致内存泄漏,而会导致可用内存大大减少)

  • webview



 

内存分配

先简单了解下Java程序内存分配:

  • 静态分配->静态存储区、方法区(主要存放static等常量静态数据)
  • 栈式分配->栈区(局部变量,容量有限的高速处理器执行,方法结束自动释放)
  • 堆式分配->堆区(动态内存分配,一般指new出来的对象实例,由gc回收)

另外栈中可以定义一个变量,变量的取值可以等于堆中的数组或者对象的地址,这个变量就是引用变量。局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。成员变量全部存储与堆中(包括基本数据类型,引用和引用的对象实体),因为它们属于类,类对象终究是要被new出来使用的。

对于Android,ActivityManager的getMemoryClass()的方法可以得到Dalvik Heap的阈值;最常用的一个缓存算法是LRU(Least Recently Use),即优先干掉最少使用的程序。

5.利用工具进行辅助排查


(一)TraceView简介   使用参考   使用参考2
Traceview是 Android平台特有的数据采集和分析工具,它主要用于分析 Android中应用程 
序的hotspot(瓶颈)。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android 
SDK中的Debug类或者利用DDMS工具。

(二)heap简介   heap的使用
heap工具可以帮助我们检查代码中是否存在会造成内存泄漏的地方。 
用heap监测应用进程使用内存情况的步骤如下: 
1.启动eclipse后,切换到DDMS透视图,并确认Devices视图、Heap视图都是打开的; 
2.点击选中想要监测的进程,比如system_process进程; 
3.点击选中Devices视图界面中最上方一排图标中的“Update Heap”图标; 
4.点击Heap视图中的“Cause GC”按钮; 
5.此时在Heap视图中就会看到当前选中的进程的内存使用量的详细情况。 
说明: 
a. 点击“Cause GC”按钮相当于向虚拟机请求了一次gc操作; 
b. 当内存使用信息第一次显示以后,无须再不断的点击“CauseGC”,Heap视图界面会定时 
刷新,在对应用的不断的操作过程中就可以看到内存使用的变化; 
c. 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。

  分析工具:TraceView, Heap, Android Memory Monitor, Hierarchy Viewer(/hai e ra kei/View层级分析), 利用log打印时间判断耗时, 手机自带GPU过度绘制检测

分析工具
 

发布了77 篇原创文章 · 获赞 3 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/haiyang497661292/article/details/85337772