Linux Kernel elemantary Knowledge

入门写的材料,凑一篇o(╥﹏╥)o... 偏简单,偏内存

什么是匿名页和文件页?

匿名页

        匿名页,没有文件背景的页面,如stack,heap,数据段等;他们没有对应的硬盘文件,因此如果要交换,只能交换到虚拟内存 zram或者Linux的swap硬盘分区,此部分页面,如果系统内存不充分,可以被swap到swapfile或者硬盘的swap分区。

(安卓手机上是默认swappiness是60,不过为了减少文件页回收,都会选择上调,更多选择压入ZRAM)

文件页

        有文件背景的页面,比如代码段、比如read/write方法读写的文件、比如mmap读写的文件;他们有对应的硬盘文件,因此如果要交换,可以直接和硬盘对应的文件进行交换。内存紧张时,非dirty的文件页可以直接drop掉,所以这个也算作MemAvailable中。

cache包含文件页(active和inactive)  zram_swap中存的是匿名页

什么是内存碎片?

            造成堆利用率很低的主要原因是就是内存碎片。当虽然有未使用的内存但不能用来满足分配请求时,就会发生该现象。有两种形式的碎片:内部碎片(internal fragmentation)和外部碎片(external fragmentation)。

外部碎片(主要问题)

        当空闲内存合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以来处理这个请求。

网上搜了个比喻,挺好理解:

        我们将信息比作货物,将存储空间比作仓库来举例子。假设,我们有编号为1、2、3、4、5、6的6间仓库库房,前天送来了一大宗货,依次装入了1、2、3、4、5号仓库,昨天又因故将4号库房的货物运走了,那么数值上说我们还有两间空仓库的空间,但是如果这时候送来两间仓库容量的货物但要求必须连续存放的话,我们实际上是装不下的。这时的4、6号仓库,就成为一种空间的碎片。由于这样的原因形成的空间碎片,我们称之为外部碎片。从上面的例子我们可以理解,外部碎片是可以通过一些措施来改善或者解决的。对于在硬盘上的外部碎片,我们通常用磁盘碎片整理来解决,对应上面的例子,就是将5号仓库的货物及时移动到新腾出的4号仓库,这样,1-4号仓库都是满的,而5、6号仓库则形成了有效的、连续的空间,能够适应新的应用要求了;对于内存中的外部碎片,我们内存管理中常用的页面管理形式,就是为了解决这个问题的。


内部碎片(这个很少了)

        当一个进程装入到固定大小的分区块(比如页)时,假如进程所需空间小于分区块,则分区块的剩余的空间将无法被系统使用

        还是沿用上面的例子,这次我们的6间仓库目前都是空置的,但是假设我们管理仓库的最小空间单位是间,今天运来了容量为2.5间仓库的货物,那也要占用我们1-3号3间仓库,尽管3号仓库还闲置着一半的空间,但是这半间仓库已经不能再利用了(因为是以间为最小单位么);这时,我们的仓库中就形成了半间仓库的空间碎片,我们称之为内部碎片。仓库的有效容量只剩下3间仓库了。

内存分配原理及大体流程

内存分配原理

        在NUMA模型中,每个CPU都有自己的本地内存节点(memory node),而且还可以通过QPI总线访问其他CPU下挂的内存节点,访问本地内存要比访问其他CPU下的内存的快约30%。Android只有一个Node 0,这个就比较简单了。

        Linux中对所有的内存进行统一管理,但由于关联不同的CPU导致访问速度不同,因此又将内存划分为节点(node);在节点内部,又进一步细分为内存域(zone),比如DMA_ZONE,Normal_ZONE,还有虚拟Movable_ZONE

ps: 提一下movable zone,就是设计用来防止碎片化,把Highmem和movable分配需求集中放到这个zone中,使得这个zone中都是可移动页面,方便页面规整。但是实际项目中这个zone基本都是空的


针对不同的用途,Linux内核将所有的物理页面划分到3类内存管理区域中:

ZONE_DMA:    该区域物理页面专供I/O设备的DMA使用,需要连续的缓冲区,不经过MMU使用物理地址访问内存。

ZONE_NORMAL:内核直接映射使用,一般存放kernal、mem_map数组等常用数据。

ZONE_HIGHMEM:高端内存,内核无法直接使用,存放用户数据、页表等不常用数据。安卓无

内核根据价值(HIGHMEM内存无依赖最廉价,DMA最昂贵数量少易用尽)为内存域定义了优先级,从高到低为:ZONE_HIGHMEM > ZONE_NORMAL > ZONE_DMA。优先选择距离较近的node,再选择优先级较高的zone。

      如果从某个zone申请内存失败,就使用node_zonelists,它定义了一个zone搜索列表(每一项代表一个zone),当从某个node的某个zone申请内存失败后,会搜索该列表,查找一个合适的zone继续分配内存。


      每个zone都有自己的伙伴系统(buddy system)。伙伴系统是基于内存块的内存管理策略,它将物理内存分成许多大小为2^n个page的内存块(其中n=0,1,2.....10,即最大内存块为4M),相同大小的内存块被链入同一个链表中。管理区描述符(struct zone)中,struct free_area用于描述伙伴系统。

      假设要分配一个n=3即2^3=8个page的内存块,算法首先搜索free_area[3]指定的链表,检查是否有空闲的内存块。如果有,直接从链表上摘取一个内存块;如果没有,算法会检查更大内存块的链表,即free_area[4]指定的链表,如果该链表有空闲块,则摘取一个空闲块并分割为大小相同的两部分(伙伴),一部分返回给内存申请者,另一部分加入到free_area[3]指定的链表中。如果free_area[4]指定的链表中也没有空闲块,则继续搜索更大的内存块链表,直至free_area[10]。

在分配页框的方式有两种:快速分配和慢速分配:

快速分配:会根据zonelist链表的优先级顺序,以zone的low阀值从相应zone的 伙伴系统中分配连续页框。

慢速分配:在快速分配失败之后执行,会根据zonelist链表的优先级顺序,以zone 的min阀值从相应zone的伙伴系统中分配连续页框。如果失败,会唤醒kswapd 内核线程,进行异步压缩、直接内存回收、oom以及轻同步压缩,进行内存回收,在这些内存回收操作的过程当中,几乎每一步会进行快速分配尝试获取内存,快速满足内存分配请求才是第一位。

内存分配流程


内存分配入口:alloc_pages(gfp_t gfp_mask, unsigned int order)

调用函数struct page *alloc_pages_current(gfp_t gfp, unsigned order)

再往下调用核心函数__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,nodemask_t *nodemask)

看下核心方法的具体流程: //参考kernel-4.19代码

1、先开始快速分配,调用get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,const struct alloc_context *ac) ac上下文包含里面的zonelist,遍历扫描zonelist,根据每个zone的水线watermark,zone_watermark_ok()查找到足够空闲的zone,在try_this_zone中查找可使用的页面返回,完成分配。在一些急迫的事务中,可以指定ALLOC_NO_WATERMARKS,这样会不会对水位进行验证。

2、 快速分配失败时,调用慢速分配方法__alloc_pages_slowpath(gfp_t gfp_mask,unsigned int order,struct  alloc_context *ac)。

3、慢速分配先进入retry_cpuset:首先调用wake_all_kswapds(order,ac),唤醒所有kswapd守护进程进行物理页面的回收(一般1-2个,linux可以设置为2个,Android考虑到功耗,一般只能设置为1个)。

4、再次调用get_page_from_freelist()进行快速分配。

5、还是分不出页面就调用__alloc_pages_direct_compact(gfp _mask, order,alloc_flags, ac,INIT_COMPACT_PRIORITY,&compact_result);在函数中继续调用 try_to_compact_pages(),继续调用for_each_zone_zonelist_nodemask()对zonelist中的每个zone进行内存压缩。在__alloc_pages_direct_compact()中再次调用get_page_from_freelist(),如果成功,函数返回page。

6、还是失败的话进入retry过程:首先唤醒所有回收线程,确保不会意外睡去。

7、尝试进行get_page_from_freelist()。

8、做一些校验,如果不能回收(reclaim),就返回nopage。

9、调用回收方法__alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,&did_some_progress)成功就返回page。

10、不成功就调用__alloc_pages_direct_compact()压缩内存,成功就返回page

11、参数判定决定是否重新从retry或者retry_cpuset开始执行。

12、到这步还是无法找到空闲页面,准备oom杀进程,调用方法__alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress)。

13、只要oom循环就一直进行retry直到找到空闲页面,进程结束就返回null。

内存回收原理及大体流程

内存回收原理

页面回收的方式(没有ZRAM,ZRAM的匿名页压缩放入ZRAM区域)

    1、页回写 存在脏页,即文件页在内存中有改动,将内存同步到设备

    2、页交换 匿名页,交换到swap分区,再次访问时换回内存

    3、页丢弃 文件页没有改动,或者不能修改,可直接丢弃

页面回收的时机

wartermark:水线,分为【WMARK_HIGH】、【WMARK_LOW】、【WMARK_MIN】。内核线程kswapd检测到不同的水线值会进行不同的处理,当空闲page数大于high时,不需要进行内存回收;当空闲page数低于low时,开始进行内存回收,将page换出到硬盘;当空闲page数低于min时,表示内存回收的压力很重,可用page数已经很少了,必须加快进行内存回收。

WMARK_MIN= min_free(单位为page),假设为min_free。(因为是每个zone各有一套watermark参数,实际计算效果是根据各个zone大小所占内存总大小的比例,而算出来的每个zone的min_free)

WMARK_LOW = WMARK_MIN * 5 / 4 + extra_free_kbytes

WMARK_HIGH = WMARK_MIN * 3 / 2

LRU(Least Recently Used),近期最少使用链表,按照近期的使用情况排列,最少使用的存在链表末尾。每个zone有5个LRU链表:

        LRU_INACTIVE_ANON 非活动匿名页lru链表,PG_active=0

        LRU_ACTIVE_ANON 活动匿名页lru链表,PG_active=1

        LRU_INACTIVE_FILE  非活动文件页lru链表,PG_active=0

        LRU_ACTIVE_FILE 活动文件页lru链表,PG_active=0

        LRU_UNEVICTABLE zone中所有禁止换出的页

页面回收时,优先回收INACTIVE的页面。

        当内存块被释放时,算法首先会检查它的伙伴是否存在,如果不存在,直接将内存块加入到对应的链表中;如果存在,将两个伙伴合并为一个更大的内存块,并继续检查该内存块的伙伴是否存在,如果存在,继续向上合并,否则链入相应的链表。

        slab缓存回收相对比较灵活,所有注册到shrinker_list中的方法都会被执行。内核默认针对每个文件系统都注册了prune_super方法,这个函数用来回收文件系统中不再使用的dentry和inode缓存;android的lowmemorykiller机制注册了选择性杀死进程的方法,回收进程使用的内存。

页面回收具体流程见shrink_zone()。

内存回收流程

        shink_zone()可以将某些页面从active链表移到inactive链表,由shrink_active_list()实现的。接着从inactive链表中选定一定数目的页面,将其放到一个临时链表中,这由函数shrink_inactive_list()完成。该函数最终会调用shrink_page_list()去回收这些页面。函数shrink_page_list()返回的是回收成功的页面数目。函数shrink_slab()会遍历shrinker链表,从而对所有注册了shrinker函数的磁盘缓存进行处理。

shrink_zone()函数的流程:

先从root_memcg开始遍历memcg:

        1、获取memcg的lru链表描述符lruvec

        2、获取memcg的swapiness(会影响扫描页框的数量)

        3、调用shrink_lruvec()对此memcg的lru链表进行处理

shrink_lruvec()函数处理文件页和匿名页lru链表的流程为:

1. 调用get_scan_count()计算每个lru链表需要扫描的页框数量,保存到nr数组中

2. 循环判断nr数组中是否还有lru链表没有扫描完成

        以活动匿名页lru链表、非活动匿名页lru链表、活动文件页lru链表、非活动文件页lru链表的顺序作为一轮扫描,每次每个lru链表扫描32个页框,并且在nr数组中减去lru链表对应扫描的数量,扫描过程中,调用shrink_list()

      一轮扫描结束后判断是否回收到了足够页框,没有回收到足够页框则跳到 2 继续循环判断nr数组

        已经回收到了足够页框,当nr数组有剩余时,判断是否要对lru链表继续扫描,如果要继续扫描,则跳到2

3. 如果非活动匿名页lru链表中页数量太少,则对活动匿名页进行一个32个页框的扫描

4. 如果太多脏页正在进行回写,则睡眠

shrink_list()在处理过程如下:

先判断是否为活动lru链表,如果是,判断非活动lru链表的页数是否过少,过少就调用shrink_active_list(),否则调用shrink_inactive_list()处理非活动链表:

活动lru链表处理流程:

1、将本地cpu的lru缓存全部清空,将lru缓存的页放到lru链表中,而其他CPU的则不处理

2、根据sc->may_writepage与sc->may_unmap从链表尾部选择要隔离的页

3、如果结点buffer_heads数量超过限制值,则会尝试对扫描到的文件页进行buffer_heads的释放,进行释放后的文件页的page->_count--

4、将所有映射了隔离页的页表项Accessed都清0

5、将最近被访问过的代码段的页移动到活动lru链表头部,其余页都移动到非活动lru链表头

6、将page->_count = 0的页进行释放

        非活动lru链表处理流程与shrink_inactive_list()函数流程差不多,首先要求当前CPU的所有lru缓存将页放入到lru链表中,然后通过isolate_lru_pages()函数从活动lru链表末尾扫描出符合要求的页,这些页会通过page->lru加入到page_list链表中,然后调用shrink_page_list()对这个page_list链表中的页进行回收处理,之后将page_list链表中剩余的页放回到它们应该放入到链表中。


shrink_page_list()主要逻辑:

1、如果页面被锁住了,放入继续将页面保留在inactive list中,后就再扫描到底时候再试图回收这些page

2、如果回写控制结构体标记了不允许进行unmap操作,将那些在pte表项中有映射到页面保留在inactive list中。

3、对于正在回写中的页面,如果是同步操作,等待页面回写完成。如果是异步操作,将page继续留在inactive list中,等待以后扫描再回收释放。

4、如果检查到page又被访问了,这个时候page有一定的机会回到active list链表中。必须满足

    a. page被访问,page_referenced检查

    b. order小于3,也就是系统趋向于回收较大的页面。对于较小的页面 趋向于保留在active list中

    c. page_mapping_inuse检查

5、如果是匿名页面,并且不在swap缓冲区中,将page加入到swap的缓冲区

6、如果页面被映射了,调用unmap函数

7、如果页面是脏页,需要向将页面内容换出,调用pateout

8、如果页面和buffer相关联,将buffer释放掉,调用try_to_release_page函数,调用__remove_mapping 将页面回收归还伙伴系统


为何需要文件系统?手机主流文件系统概况(f2fs/ext4)

文件系统:

        Linux以文件的形式对计算机中的数据和硬件资源进行管理,也就是彻底的一切皆文件,反映在Linux的文件类型上就是:普通文件、目录文件(也就是文件夹)、设备文件、链接文件、管道文件、套接字文件(数据通信的接口)等等。而这些种类繁多的文件被Linux使用目录树进行管理, 所谓的目录树就是以根目录(/)为主,向下呈现分支状的一种文件结构。不同于纯粹的ext2之类的文件系统,我把它称为文件体系,一切皆文件和文件目录树的资源管理方式一起构成了Linux的文件系统,让Linux操作系统可以方便使用系统资源。


手机主流文件系统概况:

        文件系统的作用是确定如何在本地存储中存储和检索数据。Android操作系统通常使用ext4文件系统,相较于前代ext3文件系统,ext4能快速更新文件存储。

ext4:

        ext4文件系统从ext3/ext2文件系统继承发展而来,ext4相较于前代,Ext4的文件系统容量达到1EB,而文件容量则达到16TB;采用新的数据分配方式(持久性预分配、延时分配、多块分配)以及在线碎片整理来减少磁盘碎片化,此外还增加了元数据校验和,改进了时间戳和快速文件检查等功能。常用作存放系统文件,这种IO读写少的。


主要属性介绍:

Superblock:超级块,一个文件系统有一个,每个块组也会包含超级块的副本。含有文件系统的属性和接口:

    属性:文件系统的一些参数;

    接口:mount和umount接口等。

Inode:每个文件(包括文件夹)都有一个Inode,含有文件的属性和文件属性的接口。

    属性:文件名,创建时间,修改时间,访问权限,文件保存的LBA等;

    接口:创建,删除文件夹等。

Dentry :每个目录都有一个,用来方便目录查找等。访问文件的时候,用户传递文件路径,VFS通过Hash树查找的方法直接通过路径查到最终Dentry,并找到inode,通过hash查找,最快一次就能找到,不需要逐级查找。

    属性:目录名等;

    接口:查找文件路径等。

File :对文件进行操作的接口,常用于读写操作。

    属性:文件锁,当前访问的偏移地址等;

    接口:fopen,fclose,fwrite,fread,fsync,异步读写等。

inode bitmap:标签分布表,表示标签表inode table哪些条目是占用的,用一个bit是0或者1表示空或者非空。

block bitmap:盒子分布表,表示哪些盒子里面有数据,用一个bit是0或者1表示空或者非空

For example:

查找文件 example:/root/test/a.txt

(一)通过内核找到根目录/的inode

1、根据根目录/的inode,到inode table中找到根目录/的块指针

2、通过块指针找到根目录/的数据块,根据其中的数据找到下级目录/root/对应的inode

3、根据/root/对应的inode,到inode table中找到目录/root/的元数据及块指针

4、通过块指针找到存放目录/root/的数据块,根据其中数据找到/root/test/目录对应的inode

5、根据/root/test/目录对应的inode,到inode table中找到目录/root/test/的元数据及块指针

6、通过块指针找到存放目录/root/test/的数据块,根据其中数据找到文件/root/test/a.txt对应的inode

7、根据文件/root/test/a.txt对应的inode到inode table中找到文件/root/test/a.txt的元数据及块指针

8、通过块指针找到存放文件/root/test/a.txt的数据块

II.创建文件 example:/root/test/b.txt

1、扫描inode bitmap,找到一个空闲的inode,将其标记为占用,获取其对应的inode number

2、查找目录/root/test/的数据(过程参考I),并在其中添加一条目录项(dirent)记录,文件名为/root/test/b.txt,inode number在步骤1中已经获得

3、根据inode number,在inode table中找到该inode,记录文件/root/test/b.txt的部分元数据,如inode number、权限等等

4、扫描block bitmap,找到可分配的空闲块,标记为占用,并在文件/root/test/b.txt的元数据中记录块指针

5、在数据块中写入文件数据。

III.删除文件 example:/root/test/c.txt

1、查找文件/root/test/c.txt使用的元数据信息(过程参考I)

2、查找目录/root/test/的数据(过程参考I),并删除文件/root/test/c.txt的目录项(dirent)记录

3、修改文件/root/test/c.txt的元数据,将其链接数-1

4、如果此时文件/root/test/c.txt的链接数≤0,扫描block bitmap,将分配给文件的块节点标记为空闲

5、如果此时文件/root/test/c.txt的链接数≤0,扫描inode bitmap,将其中对应的节点标记为空闲

f2fs:

        f2fs全名为“Flash Friendly File System”这是一种专门为闪存而生的,较为新型的支持Linux内核的文件系统。最早是由三星在2012年研发设计的,其目的就是为了更好的适应 NAND 一类的闪存设备(例如固态硬盘、eMMC和SD卡等),在f2fs中三星应用了日志结构档案系统的概念,使它更适合用于储存设备。f2fs的优势通俗来说就是小文件的传输速率变快了。不过问题也很明显,将相同文件存储到f2fs文件格式下相较于ext4会占用1.1倍到1.5倍的空间。

        f2fs选择 log-structured文件系统方案,并使之更加适应新的存储介质(NAND)。同时,修复了旧式日志结构文件系统的一些已知问题,如wandering tree 的滚雪球效应和高清理开销。

        根据内部几何结构和闪存管理机制(FTL),闪存存储设备有很多不同的属性,所以F2FS的设计者增加了多种参数,不仅用于配置磁盘布局,还可以选择分配和清理算法,优化性能(并行IO提高性能)。

ION内存概述

        ION是Google在Android4.0以后,为了解决内存碎片管理而引入的通用内存管理器。用户空间、内核驱动均可以使用ION分配内存,除此之外,ION也提供多个Client之间共享内存。SurfaceFlinger/Camera/Audio都常使用ION。

从2^8次方内存开始分配,一次就是1M。没有的话就是2^4,然后是2^0。本身有池

android S开始采用DMA_BUF替换ION,主要是为了让kernel社区接纳ion维护...其他变化不大

zsmalloc 用于内核内存压缩

dma_alloc_coherent DMA内存分配N个pages,目前kernel实现是从CMA中分配,物理连续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 本文以32位机器为准,串讲一些内存管理的知识点。 1. 虚拟地址、物理地址、逻辑地址、线性地址 虚拟地址又叫线性地...
    linux服务器开发阅读 2,052评论 0 0
  • 正文 0 内存模块 1 linux内存总体布局:内存分成用户态和内核态 4G进程地址空间解析 内核地址空间 进程地...
    mfdalf阅读 6,619评论 0 19
  • 进程 创建 创建进程用fork()函数。fork()为子进程创建新的地址空间并且拷贝页表。子进程的虚拟地址空间...
    梅花怒阅读 1,905评论 0 7
  • Page Cache是通过将磁盘中的数据缓存到内存中,减少磁盘I/O操作,从而提高性能。此外,还要确保Page C...
    Balram阅读 3,980评论 0 3
  • 所谓进程地址空间(process address space),就是从进程的视角看到的地址空间,是进程运行时所用到...
    tracy_668阅读 1,073评论 0 0