概述

从操作系统的角度来说,内存就是一块数据存储区域,属于可被操作系统调度的资源。现代多任务(进程)的操作系统中,内存管理尤为重要,操作系统需要为每一个进程合理的分配内存资源,所以可以从两方面来理解操作系统的内存管理机制。

第一:分配机制。为每一个进程分配一个合理的内存大小,保证每一个进程能够正常的运行,不至于内存不够使用或者每个进程占用太多的内存。

第二:回收机制。在系统内存不足打的时候,需要有一个合理的回收再分配的机制,以保证新的进程可以正常运行。回收的时候就要杀死那些正在占有内存的进程,操作系统需要提供一个合理的杀死这些进程的机制,以保证更少的副作用。

而作为一个多进程的操作系统,Android系统对内存的管理,也是有一套自己的方法的。跟PC不一样的是,Android作为一个移动操作系统,一般情况下,内存资源会比PC更少,所以就需要更加谨慎的管理内存。

Android中的内存管理机制

分配机制

Android为每个进程分配内存的时候,采用了弹性的分配方式,也就是刚开始并不会一下分配很多内存给每个进程,而是给每一个进程分配一个“够用”的量。这个量是根据每一个设备实际的物理内存大小来决定的。随着应用的运行,可能会发现当前的内存可能不够使用了,这时候Android又会为每个进程分配一些额外的内存大小。但是这些额外的大小并不是随意的,也是有限度的,系统不可能为每一个App分配无限大小的内除。

Android系统的宗旨是最大限度的让更多的进程存活在内存中,因为这样的话,下一次用户再启动应用,不需要重新创建进程,只需要恢复已有的进程就可以了,减少了应用的启动时间,提高了用户体验。

回收机制

Android对内存的使用方式是“尽最大限度的使用”,这一点继承了Linux的优点。Android会在内存中保存尽可能多的数据,即使有些进程不再使用了,但是它的数据还被存储在内存中,所以Android现在不推荐显式的“退出”应用。因为这样,当用户下次再启动应用的时候,只需要恢复当前进程就可以了,不需要重新创建进程,这样就可以减少应用的启动时间。只有当Android系统发现内存不够使用,需要回收内存的时候,Android系统就会需要杀死其他进程,来回收足够的内存。但是Android也不是随便杀死一个进程,比如说一个正在与用户交互的进程,这种后果是可怕的。所以Android会有限清理那些已经不再使用的进程,以保证最小的副作用。

Android杀死进程有两个参考条件:

进程优先级:

Android为每一个进程分配了优先级的概念,优先级越低的进程,被杀死的概率就更大。Android中总共有5个进程优先级。具体含义这里不再给出。

前台进程:正常不会被杀死

可见进程:正常不会被杀死

服务进程:正常不会被杀死

后台进程:存放于一个LRU缓存列表中,先杀死处于列表尾部的进程

空进程:正常情况下,为了平衡系统整体性能,Android不保存这些进程

回收收益:

当Android系统开始杀死LRU缓存中的进程时,系统会判断每个进程杀死后带来的回收收益。因为Android总是倾向于杀死一个能回收更多内存的进程,从而可以杀死更少的进程,来获取更多的内存。杀死的进程越少,对用户体验的影响就越小。

官方推荐的App内存使用方式是什么样的?

1、当Service完成任务后,尽量停止它。

因为有Service组件的进程,优先级最低也是服务进程,这会影响到系统的内存回收。IntentService可以很好地完成这个任务。

2、在UI不可见的时候,释放掉一些只有UI使用的资源。

系统会根据onTrimMemory()回调方法的TRIM_MEMORY_UI_HIDDEN等级的事件,来通知App UI已经隐藏了。

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

系统会根据onTrimMemory()回调方法来通知内存紧张的状态,App应该根据不同的内存紧张等级,来合理的释放资源,以保证系统能够回收更多内存。当系统回收到足够多的内存时,就不用杀死进程了。

4、检查自己最大可用的内存大小。

这对一些缓存框架很有用,因为正常情况下,缓存框架的缓存池大小应当指定为最大内存的百分比,这样才能更好地适配更多的设备。通过getMemoryClass()和getLargeMemoryClass()来获取可用内存大小的信息。

5、避免滥用Bitmap导致的内存浪费。

根据当前设备的分辨率来压缩Bitmap是一个不错的选择,在使用完Bitmap后,记得要使用recycle()来释放掉Bitmap。使用软引用或者弱引用来引用一个Bitmap,使用LRU缓存来对Bitmap进行缓存。

6、使用针对内存优化过的数据容器。

针对移动设备内存有限的问题,Android提供了一套针对内存优化过的数据容器,来替代JDK原生提供的数据容器。但是缺点就是,时间复杂度被提高了。比如SparseArray、SparseBooleanArray、LongSparseArray、

7、意识到内存的过度消耗。

Enum类型占用的内存是常量的两倍多,所以避免使用enum,直接使用常量。

每一个Java的类(包括匿名内部类)都需要500Byte的代码。

每一个类的实例都有12-16 Byte的额外内存消耗。

注意类似于HashMap这种,内部还需要生成Class的数据容器,这会消耗更多内存。

8、抽象代码也会带来更多的内存消耗。

如果你的“抽象”设计实际上并没有带来多大好处,那么就不要使用它。

9、使用nano protobufs 来序列化数据。

Google设计的一个语言和平台中立打的序列化协议,比XML更快、更小、更简单。

10、避免使用依赖注入的框架。

依赖注入的框架需要开启额外的服务,来扫描App中代码的Annotation,所以需要额外的系统资源。

11、使用ZIP对齐的APK。

对APK做Zip对齐,会压缩其内部的资源,运行时会占用更少的内存。

12、使用多进程。

一个符合Android内存管理机制的App应该是什么样的?

一个遵循Android内存管理机制的App。应该具有如下几个特点:

1、更少的占用内存。

2、在合适的时候,合理的释放系统资源。

3、在系统内存紧张的情况下,能释放掉大部分不重要的资源,来为Android系统提供可用的内存。

4、能够很合理的在特殊生命周期中,保存或者还原重要数据,以至于系统能够正确的重新恢复该应用。

App为什么要符合该内存管理机制?这样做有什么好处?

一个遵循Android的内存管理机制的App,在Android系统中,就是一个好的公民,那么系统自然是倾向于保护这些良民,而去杀死那些素质不高的人。所以符合Android内存管理机制,对Android系统和App来说,是一个双赢的过程。如果每一个App都遵循这种规则,那么Android系统就会更加流畅,也会带来更好的体验,而App可以更长时间的驻留于内存中。

在这种管理方式下,如何编写符合Android内存管理机制的App?

主要是参考官方推荐的内存使用方式,来设计和编写App。

避免创建不必要的对象。

在合适的生命周期中,合理的管理资源。

在系统内存不足时,主动释放更多的资源。

编写Android应用时,如何更少的使用内存资源?

避免创建不需要的对象。

比如使用StringBuffer来代替很多个String相加的操作。

使用原始类型来代替包装类型,int比Integer占用更少的资源。

两个并行的属性数组,优于一个包含这两个属性的对象的数组。这个在设计数据容器的时候会有意义,比如类A有两个属性A(int, String),使用 int[] 和 String[] 优于 A[]。

使用常量代替enum。

少用包装类,能够使用原始类型的,就使用原始类型。

App如果真的需要很多内存怎么办?

多进程

把消耗内存过大的模块,或者需要长期在后台运行的模块,移入到单独的进程中运行。Android会为每一个进程单独分配内存,所以理论上App就可以使用到更多的内存。但是多进程是一把双刃剑,错误的使用,会带来其他很多的问题,这里不再详细谈这个话题。

申请大内存

在<application>标签中,把largeHeap设置为true,Android系统会为该应用额外分配内存。但是不要滥用这个方法。如果一个App真的需要大内存,比如需要打开很多大图片的应用,可以使用这种方式。千万不要因为OOM而使用这种方法,这个时候更应该去检查App的代码是否不合理。

开发人员应该注意的App内存管理方式?

内存溢出

内存溢出,就是OOM,也就是内存不够用了。有一个典型的例子就是加载了很多没有经过压缩的Bitmap到内存中,这些Bitmap很大,但是又真的在被使用,必须要在内存中,所以这个时候内存就不够用了。这个时候,App再申请更多内存的时候就不行了,系统会抛出OOM。

解决这种问题:1、减少每个对象占用的内存,比如压缩图片。2、申请大内存。

内存泄露

内存泄露,就是Memory Leak,也就是本来该被GC回收后还给系统的内存,并没有被GC。多数是因为不合理的对象引用,当一个对象不再使用的时候,由于代码问题,没有正确的释放引用,就导致了内存泄露。

解决这种问题:1、通过各种内存分析工具,比如MAT,分析运行时的内存映像文件,找出造成内存泄露的代码,然后修改掉。2、适当的使用WeakReference。

Android中的内存管理机制以及正确的使用方式的更多相关文章

  1. cocos2dx中的内存管理机制及引用计数

    1.内存管理的两大策略: 谁申请,谁释放原则(类似于,谁污染了内存,最后由谁来清理内存)--------->适用于过程性函数 引用计数原则(创建时,引用数为1,每引用一次,计数加1,调用结束时, ...

  2. 【转】Android中的内存管理--不错不错,避免使用枚举类型

    原文网址:http://android-performance.com/android/2014/02/17/android-manage-memory.html 本文内容翻译自:http://dev ...

  3. Python中的内存管理机制

    Python是如何进行内存管理的 python引用了一个内存池(memory pool)机制,即pymalloc机制,用于管理对小块内存的申请和释放 1.介绍 python和其他高级语言一样,会进行自 ...

  4. 正确认识Android的内存管理机制,合理关闭进程 (一)

    随着大家收货后会有很多乐粉晒内存,为啦方便大家,在网上搜集了一些相关Andriod管理的相关机制合理管理内存,整理下发个贴. 首先要知道Android系统是基于Linux 2.6内核开发的开源操作系统 ...

  5. IOS中内存管理机制浅解

    我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是 由系统自己管理的,放在栈上).如果一个对象创建并使用后没有得 ...

  6. 2、COCOS2D-X内存管理机制

    在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...

  7. C++中的内存管理

    在C++中也是少不了对内存的管理,在C++中只要有new的地方,在写代码的时候都要想着delete. new分配的时堆内存,在函数结束的时候不会自动释放,如果不delete我分配的堆内存,则会造成内存 ...

  8. Cocos2d-x开发中C++内存管理

    由于开始并没有介绍C++语言,C++的内存管理当然也没进行任何的说明,为了掌握Cocos2d-x中的内存管理机制,是有必要先了解一些C++内存管理的知识.C++内存管理非常复杂,如果完全地系统地介绍可 ...

  9. Spark Tungsten in-heap / off-heap 内存管理机制--待整理

    一:Tungsten中到底什么是Page? 1. 在Spark其实不存在Page这个类的.Page是一种数据结构(类似于Stack,List等),从OS层面上讲,Page代表了一个内存块,在Page里 ...

随机推荐

  1. Ubuntu mysql踩坑记录

    安装: 1.sudo apt-get install mysql-server 2. apt-get isntall mysql-client 3.  sudo apt-get install lib ...

  2. .NET Core之单元测试(三):Mock框架Moq的使用

    编写一个API 新增一个接口 public interface IFoo { bool Ping(string ip); } 接口实现 public class Foo : IFoo { public ...

  3. Mysql 在线新建或重做主从

    1. 前言 以前给 Mysql 数据库做主从,都是在主服务器停服的情况下做的.但是最近有一个项目,已经上线几天了,数据库也单服务器跑了几天,才确定要给 Mysql 服务器做一个主从架构,简单的一主一从 ...

  4. AJAX优势、跨域方案及JSON数据格式和浏览器中JSON对象

    ajax 不重新加载整个网页的情况下,更新部分网页的技术 注意:ajax只有在服务器上运行才能生效,我在本地一般用phpstudy 优点: 1.优化用户体验 2.承担了一部分本该服务器端的工作,减轻了 ...

  5. MySQL索引底层数据结构

    一.何为索引? 1.索引是帮助数据库高效获取数据的排好序的数据结构. 2.索引存储在文件中. 3.索引建多了会影响增删改效率. (下面这张图为计算机组成原理内容,每查询一次索引节点,都会进行一次磁盘I ...

  6. Linux发行版Ubuntu下的Python开发环境的配置

    linux下的Python安装, 首先我们需要使用都Shell一系列的命令(前面的linux基础可不是白学的哦!) 1.更新软件安装源地址 sudo apt-get update apt-get,是一 ...

  7. OpenCASCADE(一) VS2017+OpenCASCADE+MFC 下载配置安装运行单文档程序画个基本图形

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12368154.html 一.下载OpenCASCADE 官网下载是: http://www.o ...

  8. spring boot tomcat 部署

    前几天springboot项目部署到linux中,整个过程就是个坑啊.踩坑的过程中也学到了许多.spring boot 项目部署时由于其内置了tomcat和jdk,而且还都是8. 所以部署的话就分为两 ...

  9. QuantLib 金融计算——自己动手封装 Python 接口(2)

    目录 QuantLib 金融计算--自己动手封装 Python 接口(2) 概述 如何封装一项复杂功能? 寻找最小功能集合的策略 实践 估计期限结构参数 修改官方接口文件 下一步的计划 QuantLi ...

  10. js增删class的方法

    接下来我来介绍两种方法 我们先来一段HTMl代码 <div id="bb"> 你好呀 </div> 接下来我们再来一段css样式 .ob { color:r ...