Linux中的epoll

Linux中的epoll,第1张

第一次认识epoll机制是在Android中的Handler中的Looper的唤醒和休眠机制,后者是利用Linux提供的epoll完成的。

epoll是Linux独有的机制,属于高并发下的事件驱动,是对于select和poll的性能提升。

//以下是linux-4.12下的源码

部分内容出至林学森的Android内核设计思想。

Android官网内存管理

部分出至 https://www.jianshu.com/p/94d1cd553c44

Android本质是Linux所以先从Linux说起。

Linux的内存管理为系统中所有的task提供可靠的内存分配、释放和保护机制。

核心:

虚拟内存

内存分配与释放

内存保护

将外存储器的部分空间作为内存的扩展,如从硬盘划出4GB大小。

当内存资源不足时,系统按照一定算法自动条形优先级低的数据块,并把他们存储到硬盘中。

后续如果需要用到硬盘中的这些数据块,系统将产生“缺页”指令,然后把他们交换回内存中。

这些都是由 *** 作系统内核自动完成的,对上层应用”完全透明“。

每个进程的逻辑地址和物理地址都不是直接对应的,任何进程都没办法访问到它管辖范围外的内存空间——即刻意产生的内存越界与非法访问, *** 作系统也会马上阻止并强行关闭程序,从而有力的保障应用程序和 *** 作系统的安全和稳定。

一旦发现系统的可用内存达到临界值,机会按照优先级顺序,匆匆低到高逐步杀掉进程,回收内存。

存储位置:/proc/<PID>/oom_score

优先级策略:

进程消耗的内存

进程占用的CPU时间

oom_adj(OOM权重)

Android平台运行的前提是可用内存是浪费的内存。它试图在任何时候使用所有可用的内存。例如,系统会在APP关闭后将其保存在内存中,以便用户可以快速切换回它们。出于这个原因,Android设备通常运行时只有很少的空闲内存。在重要系统进程和许多用户应用程序之间正确分配内存内对存管理是至关重要。

Android有两种主要的机制来处理低内存的情况:内核交换守护进程(kernel swap daemon)和低内存杀手(low-memory killer)。

当用户在APP之间切换时,Android会在最近使用的(LRU)缓存中保留不在前台的APP,即用户看不到的APP,或运行类似音乐播放的前台服务。如果用户稍后返回APP,系统将重用该进程,从而使APP切换更快。

如果你的APP有一个缓存进程,并且它保留了当前不需要的内存,那么即使用户不使用它,你的APP也会影响系统的整体性能。由于系统内存不足,它会从最近使用最少的进程开始杀死LRU缓存中的进程。该系统还负责处理占用最多内存的进程,并可以终止这些进程以释放RAM。

当系统开始终止LRU缓存中的进程时,它主要是自底向上工作的。系统还考虑哪些进程消耗更多的内存,从而在终止时为系统提供更多的内存增益。你在LRU列表中消耗的内存越少,你就越有可能留在列表中并能够快速恢复。

为了满足RAM的所有需求,Android尝试共享RAM来跨进程通信。它可以做到以下方式:

Android设备包含三种不同类型的内存:RAM、zRAM和storage。

注意:CPU和GPU都访问同一个RAM。

内存被拆分成页。通常每页有4KB的内存。

页面被认为是空闲的或已使用的。

空闲页是未使用的RAM。

已使用页是系统正在积极使用的RAM,分为以下类别:

干净的页面(Clean pages)包含一个文件(或文件的一部分)的一份精确副本存在存储器上。当一个干净的页面不再包含一个精确的文件副本(例如,来自应用程序 *** 作的结果)时,它就变成了脏页。可以删除干净的页,因为它们始终可以使用存储中的数据重新生成;不能删除脏页(Dirty pages),否则数据将丢失。

内核跟踪系统中的所有内存页。

当确定一个应用程序正在使用多少内存时,系统必须考虑shared pages。APP访问相同的服务或库将可能共享内存页。例如,Google Play Services 和一个游戏APP可能共享一个位置服务。这使得很难确定有多少内存属于这个服务相对于每个APP。

当 *** 作系统想要知道所有进程使用了多少内存时,PSS非常有用,因为页面不会被多次计数。PSS需要很长时间来计算,因为系统需要确定哪些页面是共享的,以及被有多少进程。RSS不区分共享页面和非共享页面(使计算速度更快),更适合于跟踪内存分配的更改。

内核交换守护进程(kswapd)是Linux内核的一部分,它将使用过的内存转换为空闲内存。当设备上的空闲内存不足时,守护进程将变为活动状态。Linux内核保持低和高的可用内存阈值。当空闲内存低于低阈值时,kswapd开始回收内存。当空闲内存达到高阈值,kswapd将停止回收内存。

kswapd可以通过删除干净的页面来回收干净的页面,因为它们有存储器支持并且没有被修改。如果进程试图寻址已删除的干净页,则系统会将该页从存储器复制到RAM。此 *** 作称为请求分页。

kswapd将缓存的私有脏页(private dirty pages)和匿名脏页(anonymous dirty pages)移动到zRAM进行压缩。这样做可以释放RAM中的可用内存(空闲页)。如果进程试图触摸zRAM中脏页,则该页将被解压缩并移回RAM。如果与压缩页关联的进程被终止,则该页将从zRAM中删除。

如果可用内存量低于某个阈值,系统将开始终止进程。

lmkd实现源码要在system/core/lmkd/lmkd.c。

lmkd会创建名为lmkd的socket,节点位于/dev/socket/lmkd,该socket用于跟上层framework交互。

小结:

LMK_TARGET: AMS.updateConfiguration() 的过程中调用 updateOomLevels() 方法, 分别向/sys/module/lowmemorykiller/parameters目录下的minfree和adj节点写入相应信息;

LMK_PROCPRIO: AMS.applyOomAdjLocked() 的过程中调用 setOomAdj() 向/proc/<pid>/oom_score_adj写入oom_score_adj后直接返回;

LMK_PROCREMOVE: AMS.handleAppDiedLocked 或者 AMS.cleanUpApplicationRecordLocked() 的过程,调用remove(),目前不做任何事,直接返回;

为了进一步帮助平衡系统内存并避免终止APP进程,可以Activity类中实现ComponentCallbacks2接口。提供的onTrimMemory()回调方法允许APP在前台或后台侦听与内存相关的事件,然后释放对象以响应应用程序生命周期或表明系统需要回收内存的系统事件。

onTrimMemory()回调是在Android 4.0(API级别14)中添加的。

对于早期版本,可以使用onLowMemory(),它大致相当于TRIM_MEMORY_COMPLETE事件。

一个专门的驱动。(Linux Kernel 4.12 已移除交给kswapd处理)。

很多时候,kswapd无法为系统释放足够的内存。在这种情况下,系统使用onTrimMemory()通知APP内存不足,应该减少其分配。如果这还不够,内核将开始终止进程以释放内存,它使用低内存杀手(LMK)来完成这个任务。

为了决定要终止哪个进程,LMK使用一个名为oom_adj_score的“out of memory”分数来确定运行进程的优先级,高分的进程首先被终止。

后台应用程序首先被终止,系统进程最后被终止。

下表列出了从高到低的LMK评分类别。第一排得分最高的项目将首先被杀死:

Android Runtime(ART)和Dalvik虚拟机使用分页(Paging)和内存映射(mmapping)来管理内存。应用程序通过分配新对象或触摸已映射页面来修改内存都将保留在RAM中,并且不能被调出。应用程序释放内存的唯一方式是垃圾收集器。

linux内核解压说明:

首先下载内核linux-4.12.4.tar.xz

然后下载工具7z.rar

然后用winrar解压7z.rar

然后安装7z

然后用7z解压linux-4.12.4.tar.xz得到linux-4.12.4.tar

最后用winrar解压更多Linux介绍可查看《Linux就该这么学》。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8696729.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-20
下一篇 2023-04-20

发表评论

登录后才能评论

评论列表(0条)

保存