美文网首页
内存优化

内存优化

作者: sanfen | 来源:发表于2019-10-18 15:55 被阅读0次

    管理内存

    节制的使用Service

    只有需要执行后台任务的时候才启动Service,当启动一个Service时,系统会倾向于将这个Service所依赖的进程保留,系统可以在LRUcache当中缓存的进程数量也会减少,导致切换程序的时候耗费更多性能。我们可以使用IntentService, 当后台任务执行结束时会自动停止。避免Service的内存泄漏。

    当界面不可见时释放内存

    当用户打开了另外一个程序,我们程序界面已经不可见的时候。我们应当将所有的和页面相关的资源进行释放。重写Activity的onTrimMemory()方法。然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发说明用户离开了程序。此时就可以进行资源释放操作了。

    当内存紧张的时候释放内存

    onTrimMemory()方法还有很多种其他类型的回调,可以在手机内存降低的时候通知我们,我们应该根据回调中传入的级别来决定如何释放应用程序的资源。

    避免在Bitmap上浪费资源

    读取一个Bitmap图片时,千万不要去加载不需要的分辨率。可以压缩图片。(获取图片的宽高而不是直接加载到内存,转换图片格式,ARGB => RGB)

    有优化过的数据集合

    Android提供了一些优化后的数据集合, SparseArray[spɑrs] 、SparseBooleanArray、LongSparseArray,使用这些API可以让我们的程序更加高效。HashMap工具类会相对比较低效,因为它需要为每一个键值对都提供一个对象入口,而SparseArray就避免掉了基本数据类型转换成对象数据类型的时间。

    知晓内存的开支情况

    • 使用枚举会比使用静态常量小号两倍以上的内存,尽可能不使用枚举。
    • 任何一个Java类,包括匿名类,内部类都要占用大概500字节的内存空间
    • 任何一个类的实例要消耗12-16字节的内存开销,因此频繁创建实例也是会在一定程度上影响内存
    • 使用HashMap,即使只设置了一个基本数据类型的键,比如int, 也会按照对象的大小来分配内存,大概是32字节而不是4字节。

    谨慎使用抽象编程

    在Android抽象编程会带来额外的内存开支。因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是也要映射到内存中,不仅占用了更多的内存,在执行效率上也会有所降低。所以需要合理的使用抽象编程。

    尽量避免使用依赖注入框架

    依赖注入看似把findViewById()这一类繁琐操作去掉,但这些框架为了寻找代码中的注解,通常都需要经历较长的初始化过程。并且将一些你用不到的对象也一并加载到内存中,这些对象会一直占用着内存空间,可能很久才会得到释放,所以可能多敲几行代码是更好的选择。

    谨慎使用多个进程

    会增加额外的内存而不是帮我们节省内存,比如音乐播放,关闭软件,已经完全由Service来控制音乐播放了,系统仍然会将许多UI方面的内存进行保留。在这种场景下就非常适合使用两个进程,一个用于UI展示,另一个用于在后台持续的播放音乐。

    分析内存的使用情况

    ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
    int heapSize = manager.getMemoryClass();
    

    每个程序都有可使用内存的上限。超过这个上限机会触发OOM

    Android的GC操作

    Android 系统会在适当的时机触发GC操作,一旦进行GC操作。就会将一些不在使用的对象进行回收。GC操作会从一个叫Roots的对象开始检查,所有它可以访问的对象说明还在使用中。GC操作会从一个叫做Roots的对象开始检查,所有它可以访问到的对象就说明还在使用当中,应该进行保留,而其他的对系那个就表示已经不再被使用了。

    Android中的内存泄漏

    Android中的垃圾回收机制并不能防止内存泄漏是因为GC不能回收被Roots引用的对象。

    高性能编码优化

    避免创建不必要的对象

    1. 字符串拼接优先使用StringBuild/StringBuffer
    2. 优先使用基本数据类型
    3. 避免自动装箱的对象频繁创建

    静态优于抽象

    若只是想调用它的某些方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,调用速度提升15%-20%

    对常量使用static final 修饰

    static int intVal = 42;  
    static String strVal = "Hello, world!";  
    

    static 在类加载的时候初始化值

    static final int intVal = 42;  
    static final String strVal = "Hello, world!";  
    

    所有的常量都会在dex文件的初始化器当中进行初始化

    使用增强for循环

    1. 对于非集合类(没有实现 Iterable接口)的数组遍历,增强型for循环和普通循环遍历原理相同,效率相同
    2. 对于集合类(实现了Iterable接口),增强型for循环的遍历其本质就是迭代器 iterator的遍历,和普通循环遍历相比,各自有自己适用的场景,比如说普通for循环比较适合List类(数组类)遍历通过下标查找数据的,而增强型for循环则比较适合链表结构的集合的遍历。

    多使用系统封装好的API

    例如:System.arraycopy()

    避免在内部调用Getters/Setters方法

    面向对象中封装的思想是不要把类内部的字段暴露给外部,而是提供特定的方法来允许外部操作相应类的内部字段。但在Android中,字段搜寻比方法调用效率高得多,我们直接访问某个字段可能要比通过getters方法来去访问这个字段快3到7倍。

    布局优化技巧

    重用布局文件

    将公共的部分提取到一个独立的布局中,使用<include/>标签引入

    仅在需要的时候才加载布局

    某个布局当中的元素不是一起显示的时候,用VISIBLE性能表现一般,可以用ViewStub。ViewStub也是View的一种,但是没有大小,没有绘制功能,也不参与布局,资源消耗非常低,可以认为完全不影响性能。

    相关文章

      网友评论

          本文标题:内存优化

          本文链接:https://www.haomeiwen.com/subject/daaimctx.html