linux so内存模型,【原创】(四)Linux内存模型之Sparse Memory Model

favicon.ico摘要:

义。关于内存模型,可以参考Memory:theflat,thediscontiguous,andthesparse3.SparseMemory本节分析的是ARM64,UMA(linux4.14中不支持ARMNUMA)下的SparseMemory模型。3.1mem_section在SparseMemory模型中,section是管理内存online/offline的最小内存单元,在ARM64中,se

背景

Read the fucking source code! --By 鲁迅

A picture is worth a thousand words. --By 高尔基

说明:

rconnect...")connfd,addr=sockfd.accept()print("Connectfrom",addr)whileTrue:#消息收发data=connfd.recv(102

Kernel版本:4.14

ARM64处理器,Contex-A53,双核

使用工具:Source Insight 3.5, Visio

1. 介绍

顺着之前的分析,我们来到了bootmem_init()函数了,本以为一篇文章能搞定,大概扫了一遍代码之后,我默默的把它拆成了两部分。

bootmem_init()函数代码如下:

ily)#AddressFamily.AF_INET获取地址族类型5print(s.fileno())#3766s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#设置端口

void __init bootmem_init(void)

{

unsigned long min, max;

min = PFN_UP(memblock_start_of_DRAM());

max = PFN_DOWN(memblock_end_of_DRAM());

early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT);

max_pfn = max_low_pfn = max;

arm64_numa_init();

/*

* Sparsemem tries to allocate bootmem in memory_present(), so must be

* done after the fixed reservations.

*/

arm64_memory_present();

sparse_init();

zone_sizes_init(min, max);

memblock_dump_all();

}

这一部分,我们将研究一下Sparse Memory Model。

在讲Linux内存模型之前,需要补充两个知识点:PFN和NUMA。

)9print(s.getsockname())#获取绑定的地址("192.168.191.3",8888)10s.listen()11c,addr=s.accept()#addr也是

1.1 physical frame number(PFN)

前面我们讲述过了虚拟地址到物理地址的映射过程,而系统中对内存的管理是以页为单位的:

page:线性地址被分成以固定长度为单位的组,称为页,比如典型的4K大小,页内部连续的线性地址被映射到连续的物理地址中;

page frame:内存被分成固定长度的存储区域,称为页框,也叫物理页。每一个页框会包含一个页,页框的长度和一个页的长度是一致的,在内核中使用struct page来关联物理页。

ttp协议的数据传输特点应用层协议。传输层使用TCP传输无状态协议,不记录用户的通信内容http1.1---->http2.0成熟稳定工作模式:  使用http双方均遵守http协议规定发送接收

如下图,PFN从图片中就能看出来了:

f286a3c0-671d-4b6d-b4e2-0f1d664982ff.jpg

至于__page_to_pfn这个实现取决于具体的物理内存模型,下文将进行介绍。

FN和NUMA。1.1physicalframenumber(PFN)前面我们讲述过了虚拟地址到物理地址的映射过程,而系统中对内存的管理是以页为单位的:page:线性地址被分成以固定长度为单位的组,称

1.2 NUMA

UMA: Uniform Memory Access,所有处理器对内存的访问都是一致的:

08cda727-4038-492f-8ab6-b2b394f9f408.jpg

从上图中可以看出,当处理器和Core变多的时候,内存带宽将成为瓶颈问题。

传输层网络层:网络层物理链路层:链路层和物理层五层(tcp/ip模型)应用层:应用层表示层会话层传输层:传输层网络层:网络层链路层:链路层物理层:物理层 协议(网络协议):在网络通信中,各方

NUMA: Non Uniform Memory Access,非一致性内存访问:

2a152e35-6392-4842-824a-9a6bec915c2a.jpg

从图中可以看出,每个CPU访问local memory,速度更快,延迟更小。当然,整体的内存构成一个内存池,CPU也能访问remote memory,相对来说速度更慢,延迟更大。目前对NUMA的了解仅限于此,在内核中会遇到相关的代码,大概知道属于什么范畴就可以了。

tsockopt(level,optname)  获取套接字选项的值1fromsocketimport*2s=socket()3print(s.type)#SocketKind.SOCK_STREAM

2. Linux内存模型

Linux提供了三种内存模型(include/asm-generic/memory_model.h):

94578e2a-f566-4730-b67c-6b8636e22323.jpg

一般处理器架构支持一种或者多种内存模型,这个在编译阶段就已经确定,比如目前在ARM64中,使用的Sparse Memory Model。

)print(data.decode())sockfd.close()TCP-clientHTTPhttp协议-->超文本传输协议 应用层协议,HTTP是基于TCP协议编码的。用途:网

Flat Memory

物理内存地址连续,这个也是Linux最初使用的内存模型。当内存有空洞的时候也是可以使用这个模型,只是struct page *mem_map数组的大小跟物理地址正相关,内存有空洞会造成浪费。

();sparse_init();zone_sizes_init(min,max);memblock_dump_all();}这一部分,我们将研究一下SparseMemoryModel。在讲Linux

Discontiguous Memory

物理内存存在空洞,随着Sparse Memory的提出,这种内存模型也逐渐被弃用了。

:将功能分开,降低了网络传输中的耦合性,每一部分完成自己的功能。可以在开发和实施的过程中各司其职。实现高内聚和低耦合的功能。高内聚:单个模块功能尽量单一低耦合:模块之间尽量减少关联和影响四层&nbsp

Sparse Memory

物理内存存在空洞,并且支持内存热插拔,以section为单位进行管理,这也是下文将分析的。

路层物理层:物理层 协议(网络协议):在网络通信中,各方必须遵守的规定。包括建立什么样的连接,消息结构等应用层:TFTPHTTPDNSSMTP传输层:TCPUDP网络层:IP 物理

Linux三种内存模型下,struct page到物理page frame的映射方式也不一样,具体可以查看include/asm-generic/memory_model.h文件中的__pfn_to_page/__page_to_pfn定义。

.listen(5)#设置监听whileTrue:#等待客户端连接print("Waitingforconnect...")connfd,addr=sockfd.accept()print("Conn

3. Sparse Memory

本节分析的是ARM64, UMA(linux4.14中不支持ARM NUMA)下的Sparse Memory模型。

39;,9999))#发起连接whileTrue:#消息收发msg=input("Msg>>")ifnotmsg:breaksockfd.sendall(msg.encode())data

3.1 mem_section

在Sparse Memory模型中,section是管理内存online/offline的最小内存单元,在ARM64中,section的大小为1G,而在Linux内核中,通过一个全局的二维数组struct mem_section **mem_section来维护映射关系。

函数的调用过程如下所示,主要在arm64_memory_present中来完成初始化及映射关系的建立:

4633ddfb-8aa9-4ffb-9268-8bad0e0b7e27.jpg

函数调用结束之后的映射关系如下图所示:

9cd67889-71bd-4934-9bd7-6f7906905297.jpg

已知一个pfn时,可以通过__pfn_to_section(pfn)来最终找到对应的struct page结构。

ckname()  获取套接字绑定的地址  # ("192.168.191.3",8888)s.getpeername()  获取连接套接字另一端的地址 # ("19

3.2 sparse_init

看看sparse_init函数的调用关系图:

53f2215e-d706-4803-9dd6-ceb0319b4889.jpg

在该函数中,首先分配了usermap,这个usermap与内存的回收机制相关,用4bit的bitmap来描述page block(一个pageblock大小通常为2的次幂,比如MAX_ORDER-1)的迁移类型:

%n)connfd.close()#关闭套接字sockfd.close()TCP-serverfromsocketimport*sockfd=socket()#创建套接字sockfd.connect(

/* Bit indices that affect a whole block of pages */

enum pageblock_bits {

PB_migrate,

PB_migrate_end = PB_migrate + 3 - 1,

/* 3 bits required for migrate types */

PB_migrate_skip,/* If set the block is skipped by compaction */

/*

* Assume the bits will always align on a word. If this assumption

* changes then get/set pageblock needs updating.

*/

NR_PAGEBLOCK_BITS

};

sparse memory模型会为每一个section都分配一个usermap,最终的物理页面的压缩,迁移等操作,都跟这些位相关,如下图所示:

c3724227-16ca-420f-9fbc-79342e748ab5.jpg

sparse_init函数中,另一部分的作用是遍历所有present section,然后将其映射到vmemmap区域空间。vmemmap区域空间,在之前的文章中也提到过。执行完后,整体的效果如下图所示:

4f6bbd18-3ee9-44e2-af0e-205a444fd513.jpg

关于Sparse Memory Model就先分析这么多,只有结合使用sparse memory的具体模块时,理解才会更顺畅。

ly  获取地址族类型  #AddressFamily.AF_INET获取地址族类型s.fileno()  获取套接字的文件描述符(每一个IO操作系统都会为其分配一个不同的正整数,该正整数即为此IO操

一不小心就容易扣细节,而一旦陷入细节,内核就容易变成魔鬼,太难了。

sockfd.bind(("127.0.0.1",9999))#绑定地址sockfd.listen(5)#设置监听whileTrue:#等待客户端连接print("Waitingfor

3ea87b29-6e7e-4f38-aba7-f29a490e9839.jpg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值