Android性能优化

来源:互联网 发布:什么软件可以看回看 编辑:程序博客网 时间:2024/06/07 08:25

内存泄露

内存泄露是指对象已经不再使用,但是因为某种原因还存在于内存中,没有及时地被垃圾回收器(GC)回收,从而造成了内存溢出

导致内存溢出的最主要的原因就是某些长存对象持有了一些其它应该被回收的对象的引用,导致垃圾回收器无法去回收这些对象,那也就出现内存泄露了。或者说是长生命周期对象持有了短生命周期对象的引用就很可能发生内存泄露

监测内存泄露的工具

  • Leakcanary
    内存泄露监测神器,出自著名的开源组织square
  • Eclipse Analysis Memory Tools(MAT)
    Eclipse的内存分析工具
  • dumpsys meminfo命令
  • ddms的heap内存监测工具
  • Android studio Monitors
    在该监听器下有图形化的分析工具,memory,cpu,gpu,network

内存溢出

垃圾回收

java中用有向图表示引用关系,可达,存在连接通路,不可达

GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请,引用,被引用,复制等,GC都要进行监控

java的内存管理就是对象的分配和释放问题,在java中,程序员需要通过关键字new为每个对象申请内存空间(基本数据类型除外),所有的对象都在堆heap中分配空间,另外对象的释放是由GC决定和执行的,在java中,内存的分配是有程序完成的,而内存的释放是由GC来完成的,这种收支两条线的方法确实减少了程序员的工作,但同时它也加重了JVM的工作,这也是java运行速度较慢的原因之一。因为GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请,引用,被引用,复制等,GC都需要进行监控

监控对象状态是为了更加准确,及时的释放对象,而释放对象的根本原则就是该对象不再被引用

GC的工作原理

为了更好理解 GC 的工作原理,我们可以将对象考虑为有向图的顶点,将引用关系考虑为图的有向边,有向边从引用者指向被引对象。另外,每个线程对象可以作为一个图的起始顶点,例如大多程序从 main 进程开始执行,那么该图就是以 main 进程顶点开始的一棵根树。在这个有向图中,根顶点可达的对象都是有效对象,GC将不回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被 GC 回收。 以下,我们举一个例子说明如何用有向图表示内存管理。对于程序的每一个时刻,我们都有一个有向图表示JVM的内存分配情况。以下右图,就是左边程序运行到第6行的示意图。
这里写图片描述

Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。

内存管理

memory
从上图可以看出,java内存区域主要分为2部分

  • 线程共享内存区:java堆,方法区
  • 线程私有内存区:虚拟机栈,本地方法栈,程序计数器,这部分内存是随着线程的产生二产生,消亡而消亡,因此不需要过多的考虑内存回收的问题,编译时就已经确定所需内存的大小

1、栈

对象的引用,数组的引用

2、堆

new出来的对象,数组

3、方法区

类信息,常量(常量池),静态变量
Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池(Class文件常量池),用于存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中

4、程序计数器

一块较小的内存空间,它是当前线程所执行的字节码的行号指示器,字节码解释器工作时通过改变计数器的值来选择下一条需要执行的字节码指令,分支,跳转,循环等基础功能都要依赖它来实现。每条线程都有一个独立的程序计数器,各个线程间的计数器互不影响,因此该区域是线程私有的

内存分配策略

java程序运行时的内存分配策略有三种,分别是静态分配,栈式分配和堆式分配,对应的三种存储策略使用的内存空间分别是静态存储区(也叫方法区),栈区和堆区。

1、静态存储区(方法区)

主要存放静态数据,全局static数据和常量,这块内存在编译时就已经分配好,并且在程序整个运行期间都会存在

2、栈区

当方法被执行时,方法内部的局部变量(其中包括基本数据类型和对象的引用)都在栈上创建,并在方法执行结束的时候这些局部变量所持有的内存都将自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量很有限

栈还分配堆中对象或数组的引用内存空间

3、堆区

又称为动态内存分配,通常就是指程序运行时直接new出来的内存,也就是对象的实例,数组,这部分内存在不使用时将由java垃圾回收器来负责回收

JVM

电量优化

布局优化

性能优化

1、使用IntentService

使用IntentService有两个好处,一个是任务执行完的时候,IntentService会自动结束,不会像Service那样长期呆在后台;另外一个是不需要手动开辟子线程去执行耗时操作,因为IntentService已经帮我们做了这些工作

2、使用优化的数据容器

  • SparseArray稀疏数组,替代HashMap
  • SparseBooleanArray 替代HashMap
  • LongSparseArray
  • ArrayMap

3、使用线程池管理线程

在需要开辟子线程去执行耗时任务的时候不要通过new Thread的方式,因为创建和销毁一个线程所消耗的资源可能会比执行这个线程所消耗的资源更多,所以我们应该使用线程池技术,去统一的管理和缓存线程,提高效率

4、优化Bitmap

内存溢出大部分情况都是大图片导致的,大图片占用的内存是像素总数x每个像素占用的字节数,一张很小的图片都有可能占用很大的内存,所以我们很有必要对图片进行压缩,缓存图片(三级缓存),复用Bitmap(inBitmap属性),回收Bitmap(recycle())

0 0
原创粉丝点击