qq内核网站源码分享获取,qq教程网站源码

很多朋友对于qq内核网站源码分享获取和qq教程网站源码不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!

一、mmap基础概念

mmap即memorymap,也就是内存映射。mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read、write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。

如下图所示:

mmap的作用,在应用这一层,是让你把文件的某一段,当作内存一样来访问。将文件映射到物理内存,将进程虚拟空间映射到那块内存。这样,进程不仅能像访问内存一样读写文件,多个进程映射同一文件,还能保证虚拟空间映射到同一块物理内存,达到内存共享的作用。

mmap具有如下的特点:

mmap向应用程序提供的内存访问接口是内存地址连续的,但是对应的磁盘文件的block可以不是地址连续的;mmap提供的内存空间是虚拟空间(虚拟内存),而不是物理空间(物理内存),因此完全可以分配远远大于物理内存大小的虚拟空间(例如16G内存主机分配1000G的mmap内存空间);mmap负责映射文件逻辑上一段连续的数据(物理上可以不连续存储)映射为连续内存,而这里的文件可以是磁盘文件、驱动假造出的文件(例如DMA技术)以及设备;mmap由操作系统负责管理,对同一个文件地址的映射将被所有线程共享,操作系统确保线程安全以及线程可见性;mmap的设计很有启发性。基于磁盘的读写单位是block(一般大小为4KB),而基于内存的读写单位是地址(虽然内存的管理与分配单位是4KB)。

换言之,CPU进行一次磁盘读写操作涉及的数据量至少是4KB,但是进行一次内存操作涉及的数据量是基于地址的,也就是通常的64bit(64位操作系统)。mmap下进程可以采用指针的方式进行读写操作,这是值得注意的。

二.虚拟内存?虚拟空间?

其实是一个概念,前一篇对于这个词没有确切的定义,现在定义一下:

虚拟空间就是进程看到的所有地址组成的空间,虚拟空间是某个进程对分配给它的所有物理地址(已经分配的和将会分配的)的重新映射。

而虚拟内存,为啥叫虚拟内存,是因为它就不是真正的内存,是假的,因为它是由地址组成的空间,所以在这里,使用虚拟空间这个词更加确切和易懂。(不过虚拟内存这个词也不算错)

虚拟空间原理

物理内存

首先,物理地址实际上也不是连续的,通常是包含作为主存的DRAM和IO寄存器

以前的CPU(如X86)是为IO划分单独的地址空间,所以不能用直接访问内存的方式(如指针)IO,只能用专门的方法(in/read/out/write)诸如此类。现在的CPU利用PCI总线将IO寄存器映射到物理内存,所以出现了基于内存访问的IO。还有一点补充的,就如同进程空间有一块内核空间一样,物理内存也会有极小一部分是不能访问的,为内核所用。

三个总线

这里再补充下三个总线的知识,即:地址总线、数据总线、控制总线

地址总线,用来传输地址数据总线,用来传输数据控制总线,用来传输命令

比如CPU通过控制总线发送读取命令,同时用地址总线发送要读取的数据虚地址,经过MMU后到内存

内存通过数据总线将数据传输给CPU。虚拟地址的空间和指令集的地址长度有关,不一定和物理地址长度一致,比如现在的64位处理器,从VA角度看来,可以访问64位的地址,但地址总线长度只有48位,所以你可以访问一个位于2^52这个位置的地址。

虚拟内存地址转换(虚地址转实地址)

上面已经明确了虚拟内存是虚拟空间,即地址的集合这一概念。基于此,来说说原理。

如果还记得操作系统课程里面提到的虚地址,那么这个虚地址就是虚拟空间的地址了,虚地址通过转换得到实地址,转换方式课程内也讲得很清楚,虚地址头部包含了页号(段地址和段大小,看存储模式:页存储、段存储,段页式),剩下部分是偏移量,经过MMU转换成实地址。

存储方式

虚拟地址头部为页号通过查询页表得到物理页号,假设一页时1K,那么页号*偏移量就得到物理地址

虚拟地址头部为段号,段表中找到段基地址加上偏移量得到实地址

二、mmap原理

mmap函数创建一个新的vm_area_struct结构,并将其与文件/设备的物理地址相连。

vm_area_struct:

linux使用vm_area_struct来表示一个独立的虚拟内存区域,一个进程可以使用多个vm_area_struct来表示不用类型的虚拟内存区域(如堆,栈,代码段,MMAP区域等)。

vm_area_struct结构中包含了区域起始地址。同时也包含了一个vm_opt指针,其内部可引出所有针对这个区域可以使用的系统调用函数。从而,进程可以通过vm_area_struct获取操作这段内存区域所需的任何信息。

进程通过vma操作内存,而vma与文件/设备的物理地址相连,系统自动回写脏页面到对应的文件磁盘上(或写入到设备地址空间),实现内存映射文件。

[内核资料领取,](https://docs.qq.com/doc/DTmFTc29xUGdNSnZ2)

[Linux内核源码学习地址。](https://ke.qq.com/course/4032547?flowToken=1044435)

内存映射文件的原理:

首先创建虚拟区间并完成地址映射,此时还没有将任何文件数据拷贝至主存。当进程发起读写操作时,会访问虚拟地址空间,通过查询页表,发现这段地址不在物理页上,因为只建立了地址映射,真正的数据还没有拷贝到内存,因此引发缺页异常。缺页异常经过一系列判断,确定无非法操作后,内核发起请求调页过程。

最终会调用nopage函数把所缺的页从文件在磁盘里的地址拷贝到物理内存。之后进程便可以对这片主存进行读写,如果写操作修改了内容,一定时间后系统会自动回写脏页面到对应的磁盘地址,完成了写入到文件的过程。另外,也可以调用msync()来强制同步,这样所写的内存就能立刻保存到文件中。

mmap内存映射的实现过程,总的来说可以分为三个阶段:

(一)进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域

进程在用户空间调用库函数mmap,原型:void*mmap(void*start,size_tlength,intprot,intflags,intfd,off_toffset);在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址为此虚拟区分配一个vm_area_struct结构,接着对这个结构的各个域进行了初始化将新建的虚拟区结构(vm_area_struct)插入进程的虚拟地址区域链表或树中

(二)调用内核空间的系统调用函数mmap(不同于用户空间函数),实现文件物理地址和进程虚拟地址的一一映射关系

为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体(structfile),每个文件结构体维护着和这个已打开文件相关各项信息。通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为:intmmap(structfile*filp,structvm_area_struct*vma),不同于用户空间库函数。内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址。通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这片虚拟地址并没有任何数据关联到主存中。

(三)进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存(主存)的拷贝

注:前两个阶段仅在于创建虚拟区间并完成地址映射,但是并没有将任何文件数据的拷贝至主存。真正的文件读取是当进程发起读或写操作时。

进程的读或写操作访问虚拟地址空间这一段映射地址,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。调页过程先在交换缓存空间(swapcache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。之后进程即可对这片主存进行读或者写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应磁盘地址,也即完成了写入到文件的过程。

注:修改过的脏页面并不会立即更新回文件中,而是有一段时间的延迟,可以调用msync()来强制同步,这样所写的内容就能立即保存到文件里了。

三、mmap的I/O模型

mmap也是一种零拷贝技术,其I/O模型如下图所示:

import&34;\nimport<sys/stat.h>\n@interfaceViewController()\n\n@end\n\n@implementationViewController\n\n-(void)viewDidLoad{\n[superviewDidLoad];\n\nNSString*path=[NSHomeDirectory()stringByAppendingPathComponent:@&34;];\nNSLog(@&34;,path);\nNSString*str=@&34;;\n[strwriteToFile:pathatomically:YESencoding:NSUTF8StringEncodingerror:nil];\n\nProcessFile(path.UTF8String);\nNSString*result=[NSStringstringWithContentsOfFile:pathencoding:NSUTF8StringEncodingerror:nil];\nNSLog(@&34;,result);\n}\n\n\nintMapFile(constchar*inPathName,void**outDataPtr,size_t*outDataLength,size_tappendSize)\n{\nintoutError;\nintfileDescriptor;\nstructstatstatInfo;\n\n//Returnsafevaluesonerror.\noutError=0;\n*outDataPtr=NULL;\n*outDataLength=0;\n\n//Openthefile.\nfileDescriptor=open(inPathName,O_RDWR,0);\nif(fileDescriptor<0)\n{\noutError=errno;\n}\nelse\n{\n//Wenowknowthefileexists.Retrievethefilesize.\nif(fstat(fileDescriptor,&statInfo)!=0)\n{\noutError=errno;\n}\nelse\n{\nftruncate(fileDescriptor,statInfo.st_size+appendSize);\nfsync(fileDescriptor);\n*outDataPtr=mmap(NULL,\nstatInfo.st_size+appendSize,\nPROT_READ|PROT_WRITE,\nMAP_FILE|MAP_SHARED,\nfileDescriptor,\n0);\nif(*outDataPtr==MAP_FAILED)\n{\noutError=errno;\n}\nelse\n{\n//Onsuccess,returnthesizeofthemappedfile.\n*outDataLength=statInfo.st_size;\n}\n}\n\n//Nowclosethefile.Thekerneldoesn’tuseourfiledescriptor.\nclose(fileDescriptor);\n}\n\nreturnoutError;\n}\n\n\nvoidProcessFile(constchar*inPathName)\n{\nsize_tdataLength;\nvoid*dataPtr;\nchar*appendStr=&34;;\nintappendSize=(int)strlen(appendStr);\nif(MapFile(inPathName,&dataPtr,&dataLength,appendSize)==0){\ndataPtr=dataPtr+dataLength;\nmemcpy(dataPtr,appendStr,appendSize);\n//Unmapfiles\nmunmap(dataPtr,appendSize+dataLength);\n}\n}\n@end

文章分享结束,qq内核网站源码分享获取和qq教程网站源码的答案你都知道了吗?欢迎再次光临本站哦!

Published by

风君子

独自遨游何稽首 揭天掀地慰生平