您的位置:首页 > 移动开发 > Android开发

Android异常与性能优化二

2018-01-22 20:41 274 查看
一、内存泄漏

1、





②静态存储区

也叫方法区,主要存放静态数据,全局变量。并且在静态存储区中存储的数据,在整个程序运行期间都存在。

③栈区

方法中的局部变量,会在栈区分配存储空间,并且在方法执行完成后,栈区所持有的变量空间会被自动释放。因为栈区内置于存储器当中,所以处理效率很高,但是栈区的内存空间,容量有限。

④堆区

在堆区又称为动态内存分配,通常就是我们new对象分配出来的内存,这部分的内存将会在不使用的时候,由java的内存回收器进行回收

⑤栈区在方法体内定义了一些基本的方法变量和对象的引用变量都是在方法的栈内存中分配的,当在一段方法中定义一个变量时,java就会在栈内存中为变量分配内存空间,当超过方法的作用域之后,方法也就无效了,分配给它的内存空间也将被释放掉,这时栈区的所释放的空间就可以被其它方法所使用。

而堆区存储的是所有用new创建的对象,还有数组,在堆中分配的内存,将由java的内存回收器自动进行管理。其中产生的数组或对象还可以在栈中定义一个特殊的变量,而这个变量就是在栈区存储内存的地址。

2、

内存的分配是由开发人员通过new来完成的,内存的回收是通过gc自动完成的。减轻了我们的工作,但是也加重了java虚拟机的工作。这也是为什么java相对于c、c++运行相对较慢的原因。



3、



4、





①单例

正确的方法是使用下面的没有被注释的代码,使用应用的application,而不是使用activity,这样activity可以被回收



②内部类:在java中,内部类默认会持有外部类的引用

解决办法是将内部类设置为静态的,这样静态内部类就不会持有外部类的引用,从而就不会有内存泄漏的问题

③handler:

handler是非静态内部类,所以会持有外部类的引用,由于handler中有未完成的message,message又关联到handler,handler又关联到外部的activity,导致activity想要被回收的时候无法被回收,造成内存泄漏

容易造成内存泄漏的写法,因为该handler是activity的的非静态内部类的实例,所以它持有外部类的引用。handler的消息队列是在looper中不断轮询处理消息,当activity退出的时候,消息队列中还有未处理的消息,或正在处理的消息,而handler中的message又持有了handler的实例引用,从而导致activity想要被回收时无法被回收,造成了内存的泄漏。Handler实际上是一个ThreadLocalStorage,它的生命周期和activity是不一样的。因此,这样写handler的方式很难保证生命周期和handler是一样的,所以经常会导致内存泄漏。



④避免使用static成员变量:

改变量的声明周期是和整个app的生命周期是一样的,如果app是常驻内存的,那么即使app被切换到后台,这部分变量也是不会被释放的。当后台进程被回收之后,static的变量是不安全的。对static造成内存泄漏的修复方法,在类设计的时候,是不是在初始化的时候,设置为静态成员。是不是可以考虑设置为懒加载,尽量避免static变量。如果架构上一定要涉及到了static变量,一定要对这些变量的声明周期进行管理起来。

⑤资源未关闭造成的内存泄漏。

cursor、文件、bitmap这些存在于activity中,当activity被销毁的时候,释放资源,否则,这些资源不会被回收,造成内存泄漏。

⑥Asynctask造成的内存泄漏

原因和handler比较类似。也是费静态内部类使用了外部类的引用,如果在activity的onDestroy方法中使用了cancle方法,就可以避免内存泄漏

正确的写法是:

将handler改为静态内部类,并在handler的内部持有activity的弱引用



5、



①分配机制:内存实际上就是一块数据存储区域,而且它是属于可以被操作系统调度的资源,在现在多进程的操作系统当中,内存管理十分重要。操作系统会为每一个进程合理地分配内存大小,从而才能保证每一个进程能够正常地运行,而不至于内存不够使用或者每个进程占用太多的内存,这就是操作系统的分配机制的概念。

②回收机制:在系统内存不足的时候,有一个合理的回收再分配的内存机制。从而才能保证,新的进程能够正常运行。回收的时候就要杀死那些占用系统资源的内存,操作系统需要提供一个合理的杀死这些进程的机制,以保证把副作用降到最低。

6、



①分配机制:Android在为每一个进程分配内存的时候,它采用了一个弹性的分配方式。一开始不会为这个app分配太多的内存,而是为每一个app的进程分配一个小的量,而这个小的量是根据每个移动设备ram尺寸大小来决定的。随着app的不断运行,可能会发现当前app的内存已经不够使用了,这时候Android又会为每个app分配额外的内存大小,额外的内存大小不是随意分配的,它是有限度的,因为Android的内存大小是有限制的,所以系统不可能为每个app分配无限大的内存。Android系统的分配机制,就是让更多的进程存活在app当中,这样当用户重新启动app的进程的时候,它就不需要重新创建进程,直接复用已存在的进程就可以了,这样就减少了启动时间,提高了用户的体验。

②回收机制:保存尽可能多的数据,运行尽可能多的进程,减少了应用的启动进程。当内存不够使用的时候,需要回收内存的时候,Android就会杀死其它进程,来回收足够的内存,从而开启新的进程。这里,对Android进程的分配有一个优先级的概念,主要分为五个进程:前台进程、可见进程、服务进程、后台进程、空进程,优先级越低的进程,被系统回收的可能性越大。前台进程、可见进程、服务进程在正常情况下是不会被系统杀死的。而后台进程会被保存在一个缓冲列表中,就是lru,最近最少使用的缓存方式。先杀死的进程,处于列表的尾部。空进程实际上是为了平衡整个系统的性能。回收效应:当Android杀死进程的时候,它会判断每个进程杀死后的回收效应,因为Android总是倾向于杀死一个能回收更多效应的进程。可以通过杀死更多进程来获取更多内存。杀死的进程越少,对用户体验的影响也越小。

7、



8、





①当service完成任务后,尽量停止它。

service进程优先级是比较低的,叫服务进程,会影响掉内存回收。可以用intentservice来替代service来完成任务。intentservice是继承service的,它也是一个服务,但是它不同于service的地方是,service是默认在主线程中执行的,所以service中不可以做耗时操作,intentservice内部是开启一个子线程,在它的handleintent方法中可以做一些耗时的操作。第二个就是intentservice执行完成后会自动退出,不像service需要手动调用stopservice来退出。如果忘了关闭service,会造成内存泄漏。

②ui不可见的时候,释放掉一些只有ui使用的资源

根据ontrimomery来通知回收掉一些资源

③在系统内存紧张的时候,尽可能多的释放掉一些非重要资源

在ontrimmemory这个方法中通知内存紧张状态,app会根据不同的内存紧张等级,释放掉一些资源。

④避免滥用bitmap导致的内存浪费

根据当前设备的分辨率来设置bitmap是我们的选择,在使用bitmap之后,一定要调用bitmap的recycle方法释放掉bitmap在c中的内存,也可以通过软引用来引用一个bitmap,然后使用lru对bitmap进行缓存算法

⑤使用针对内存优化过的数据容器,因为它消耗的内存是常量的两倍多

尽量少用枚举常量,

⑥避免使用依赖注入框架

比如框架需要扫描app中的注解,带来额外的资源消耗

⑦使用zip对齐的apk

主要是因为zip是一个工具,它会压缩内部的资源,运行时会占用更少的内存

⑧使用多进程

需要定位,开启一个定位进程,又如webview,不单独开进程的话会引起内存泄漏,

9、



内存溢出:实际上就是oom,遇到最多的还是bitmap,对没有经过压缩的bitmap放到内存中,对内存的占用实际上是非常大的,这时再申请更多内存,系统就会抛出oom异常。解决办法就是压缩图片、使用inbitmapsize、对bitmap进行裁剪、及时对bitmap进行回收

内存泄漏:本来应该被垃圾回收器gc回收掉的内存,没有被回收掉,多数是不合理的对象引用,比如非静态内部类持有外部类的引用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: