免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: chenrvmldd
打印 上一主题 下一主题

也谈谈这四年来对内核的研究 [复制链接]

论坛徽章:
0
51 [报告]
发表于 2011-07-04 09:29 |只看该作者
回复 34# chenrvmldd

内存管理部分都是东拼西凑,相互验证猜测的,回答下Lz:
一:
1.内核启动先执行bios, bios则通过探测总线获取所有的内存区。
2,setup.s中会搬运这些探测结果到memory 0页
3.内核引导,读取这些内存区信息,e820。先验证,若通过直接用,否则猜测使用。继而形成PGlist, zone等区域

二:
boatload则依赖于不同硬件体系结构,一般会预先定义好内存BANK。并在一个文件中定义。形如lowmemory.S
内核启动时直接传入

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 感谢分享

查看全部评分

论坛徽章:
0
52 [报告]
发表于 2011-07-04 09:32 |只看该作者
另外期待lz关于体系结构的大作

论坛徽章:
0
53 [报告]
发表于 2011-07-04 11:24 |只看该作者
今天上来看了一下,发现几个兄弟做了一些回复,基本上和我理解的差不多,可是,我喜欢兄弟们更深的去思考一下,问题背后的不同设计的差异,为什么会使用A设计而不使用B设计,目的是什么?这才是我提问题的目的,其实,工作不到1年的时间,我发现,知识没有思维重要,这也就解释了公司里面有些人工作了5年还是老样子,有的人工作才1-2年就成为项目负责人(当然这还有其他的原因),知识学起来很快,可是思维就没有那么快形成!
先回答几个兄弟的问题:
Smalloc 兄弟的问题:中断的重要性,你说的非常对,中断让整个系统的设计变的复杂,但是中断本身并不复杂,其实操作系统中任何一部分都是重要的,没有最重要,也没有相对重要,只是说内存管理比价复杂,难以理解,中断本身不难理解,但是它的出现使得系统变的复杂,这正是我想表达的!
futex:这个兄弟说的非常的对,可是中断你觉得难理解吗?如果你学过计算机组成原理,相信你也写过中断处理程序吧?8259A
懂医术的厨师:这个兄弟说,内存管理是东凑西拼出来的,这句我不太理解,希望你能详细的解释一下!

下面公布一下我理解的答案:
其实“懂医术的厨师:”这个兄弟的答案和我的差不多:
我先把他的答案贴出来,然后再补充一下:
一:
1.内核启动先执行bios, bios则通过探测总线获取所有的内存区。
2,setup.s中会搬运这些探测结果到memory 0页
3.内核引导,读取这些内存区信息,e820。先验证,若通过直接用,否则猜测使用。继而形成PGlist, zone等区域

二:
boatload则依赖于不同硬件体系结构,一般会预先定义好内存BANK。并在一个文件中定义。形如lowmemory.S
内核启动时直接传入
关于第一个问题,我想说的,回答的非常好:就是在第三个小点漏了一点:e820形成之后到PGLIST和zone这块,其实还应该有过关于bootmem这样的一个过程,bootmem是初始化的时候为各个初始化模块提供内存管理的!
第二个问题:其实在嵌入式的bootloader中,我们是根据不同的板子信息,在板子的/include/configs下面的板子头文件中定义了内存的大小,物理地址的编址,而在x86的体系结构下,我们是通过“int 0x15,功能号为0xe820:的BIOS调用
其实这个为问题的本身,我觉得不是特别的难,看过linux内核情景分析的都知道,看过嵌入式的Uboot也清楚,可是我系统通过这个问题:让大家进一步思考:为什么嵌入式的Bootloarder和PC机下的bootloader就应该不一样了?
其实我的理解是:在嵌入式领域:Uboot和内核都是靠我们自己去移植的,因为,我们会自己去配置自己的硬件(比如:nandflash,nor flash,等等,地址都是我们自己去编的,大小,我们在移植也已经订好了,以后就不会改变了),比如不同的flash,不同的phy,等等,不同的应用会导致硬件差别特别的大,而且灵活性也很大!
而在PC机领域就不存在上面的问题:比如,有可能内存条我们会自己变换,如果我们变换一次就需要修改操作系统,那么对于操作系统的用户来讲,那是不可能的!

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 感谢分享

查看全部评分

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
54 [报告]
发表于 2011-07-04 11:27 |只看该作者
本帖最后由 smalloc 于 2011-07-04 11:35 编辑

不妨就着帖子再把内存管理之疑难和要点在详尽讨论下。
我先起个头:主要针对内存管理各个层次和各个子功能相互关联,以及又同步异

步并发导致的难点提出自己的几点疑问,希望大家能给予解答。
首先列举内存管理相关的几个子模块,只求通用:
TLB,MMU,cache,内存中的页目录和页表(统一称页表),权限和异常
以上为处理器部分,以下为OS部分。
物理页管理(page),高端内存,进程地址空间的线性地址管理和缺页,slab和伙伴系统,
块IO和磁盘的页高速缓存。

我先尝试提一个开场问题:
vfree会释放占有的vm_area吗?为什么要那样做?

评分

参与人数 1信誉积分 +2 收起 理由
Godbach + 2 感谢分享

查看全部评分

论坛徽章:
0
55 [报告]
发表于 2011-07-04 11:59 |只看该作者
楼上兄弟说的是vm_struct 还是 vmap_area?

论坛徽章:
0
56 [报告]
发表于 2011-07-04 12:25 |只看该作者
如果是vmap_area,俺冒死试着回答一下该问题:不会,而是把该对象放在一个队里中,累计到一定数目后一起释放,为啥呢?我想可能是每次释放一个vmap_area同时也要flush一下该区域的tlb(页表变了),在smp系统中flush tlb代价是很高的(其他cpu都要invalidation其tlb该区域内容并重新载入),延迟并累积一定数目的vmap_area后一次flush其相关的tlb range会极大的减少tlb的刷新和重载次数。
    不知俺说的对不对?

论坛徽章:
0
57 [报告]
发表于 2011-07-04 14:23 |只看该作者
纯帮顶

论坛徽章:
0
58 [报告]
发表于 2011-07-04 16:30 |只看该作者
回复 54# smalloc


我来回答一下smalloc兄弟的问题吧:
Vfree()这系统调用对应的是vmalloc,我们还知道系统调用中还有kmalloc和kfree,那么他们之间到底有什么联系?弄清楚smalloc兄弟提出的这个问题和vmalloc和kmalloc(这个问题,我当时面试一家大公司的时候,面试官曾经问过这个问题),最重要的是理解vmalloc和vfree在什么前提下提出来的,他们背后的原理是什么,弄懂原理性的东西,我觉得smalloc兄弟的问题就会迎刃而解了!
Vmalloc和vfree是在非连续存储区管理中提供出来的接口,那么为什么会有非连续存储区管理了?这到底是解决一个什么样的问题了?
在ULK这本书中有一段话如下:
把存储器映射到一组连续的页框是最好的选择,这样会充分利用高速缓存并达到较低的平均访问时间。不过,如果对存储区域的请求并不是很频繁,那么通过连续的线性地址来访问非连续的页框这样一种分配模式就会有很有意义。这种模式的主要缺点是避免了外部碎片,而缺点是必须打乱内核页表。显然非连续的存储区的大小必须是4096的倍数。Linux在几个方面使用非连续存储区。例如:为活动的交换区分配数据结构,为模块分配空间,或者给某些I/O驱动程序分配缓冲区。
好了,其实这段话并不长,但是蕴藏了很多问题和玄机在里面!
第一个疑问:把存储器映射到一组连续的页框是最好的选择,这样会充分利用高速缓存并达到较低的平均访问时间。这样为什么是最好的选择了? 为什么会充分利用高速缓存了?
很简单的一个道理:高速缓存也就是我们所说的cache,cache是基于局部性原来提出的:连续的页框,在局部的时间内被缓存在cache中,降低了访问页框的时间。如果这个时候,页框不是连续的,线性地址是连续的会局部时间内这些线性地址会被访问,但是他们对应的页框不是连续的,有的会在cache中,有的不在,那么势必会降低cache利用效率(其实说直白一点:就是连续的页框在cache中的访问时候的命中的机率要比非连续的要高)
第二个疑问:缺点是打乱了内核页表,为什么会打乱了内核页表?打乱了内核页表有什么坏处?
从这段话,我们可以知道在原来的连续的页框的情况下,内核是什么样的有序的,这种有序是一个什么样的有序了?我们知道线性地址和物理地址有个这样的关系线性地址-3G=物理地址(在896M一下会有这样的对应关系),所以在页表初始化的时候,前面896M对于内核页表来讲是直接映射过来的,在系统初始化的时候就建立好了映射关系,注意这个和用户进程的页表是不一样的!那么3G+896M后就会存在不一一映射的情况!这种有序根据局部性原理会大大提高cache的命中率,但是如果这种顺序被打乱了,势必导致cache的命中率会降低(在一段时间访问的物理地址不连续)!
第三个疑问:连续的页框这种模式的缺点是外部碎片?显然非连续存储区的大小是4096的倍数?
假设如果这个时候只有10个页框,这10个页框是非连续的(3个连续,其他的都不连续),10个页框的大小正好是10*4K=40K,这个时候我要通过kmalloc申请4个连续的页框,势必会失败,但是我的内存可用的空间大于4个页框,这也是为什么会提出vmalloc和vfree的问题了!
下面来说说在Linux中它是如何来实现的,下面也通过一些程序来验证我的想法:
ULK书上这么说的:
为非连续内存保留的线性地址空间的其实地址由VMALLOC_START宏定义,而末尾地址由VMALLOC_END宏定义,那么如果我通过vmalloc分配的地址范围一定会在VMALLOC_START和VMALLOC_END之间了,通过一个程序来验证:
  1. #ifndef __KERNEL__
  2. #define __KERNEL__
  3. #endif
  4. #ifndef __MODULE__
  5. #define __MODULE__
  6. #endif


  7. #include <linux/module.h>
  8. #include <linux/kernel.h>
  9. #include <linux/init.h>
  10. #include <linux/vmalloc.h>
  11. #include <linux/mm.h>
  12. #include <asm/pgtable.h>
  13. #include <asm/uaccess.h>

  14. int  __init test_init(void)
  15. {
  16.         char *vmalloc_mem;
  17.         size_t count=128;

  18.         printk("VMALLOC_START=:%x\n",VMALLOC_START);

  19.     vmalloc_mem=(char *)vmalloc(count);
  20.         printk("vamalloc_mem=:%x\n",vmalloc_mem);
  21.         printk("VMALLOC_END=:%x\n",VMALLOC_END);

  22.         return 0;
  23. }
  24. void __exit test_exit(void)
  25. {
  26.         printk("Bye test\n");
  27.         return;
  28. }
  29. module_init(test_init);
  30. module_exit(test_exit);
  31. MODULE_LICENSE("GPL");
复制代码
  1. /home # insmod vmalloc_test.ko
  2. VMALLOC_START=:c8000000
  3. vamalloc_mem=:c8060000
  4. VMALLOC_END=:f0000000
复制代码
发现我们新申请的区域果然在VMALLOC_START和VMALLOC_END之间

对于非连续区域的管理vm_struct数据结构来描述的,它的管理方式应该和vma的管理差不多,其实可以通过vmalloc函数和vfree函数的实现可以看的出来,对于vm_struct数据结构,在vmalloc中会通过kmalloc分配一个物理空间给vm_struct来描述新的连续的线性地址区域!
当通过vfree释放的时候会相应的调用kfree释放vm_struct的数据结构占用的空间

论坛徽章:
0
59 [报告]
发表于 2011-07-04 16:34 |只看该作者
希望大家都过来发表一下自己的意见和见解,把自己不清楚的地方贴出来,大家共同来讨论,我相信每个人在学内核的时候都会有很多问题不清楚,既然我们在论坛上,那么我们就是兄弟,就应该像一家人一样,大家互相帮组,把各自的不懂的问题贴出来,让更多的人帮助你,我也希望看到别人的问题的时候,兄弟们积极一点帮助别人,当我们遇到问题的时候别人也会积极的来帮助我们!希望大家积极起来!

论坛徽章:
0
60 [报告]
发表于 2011-07-04 16:48 |只看该作者
第三个问题:
进程管理相关的:
第一个小问:记得在学操作系统的时候,老师曾经提过进程上下文切换,说进程上下文切换比较耗时,在这点上线程要比进程有优势,那么进程的上下文是什么了?切换的时候都做了些什么?我相信这个对于看过内核代码的兄弟都比较容易,那好,我们知道在进程切换的时候:在古老的Linux中采用的方法和现代版本的Linux中采用的是不同办法?这两个办法有什么差别了?为什么新版本的内核采用现在的切换机制?其实,这个问题我想考察大家对Linux各种版本之间的关系,因为Linux内核不停的再优化,为什么会这么优化基于什么样的考虑?这个可以从内核不停的修改这方面可以看得出,这样也可以为我们去优化内核提供思路

第二个小问:在Linux中创建进程通过fork调用,按照fork调用的实现,它是写时复制机制,我们知道新创建的内核时复制的父进程的,那么父进程复制的是它的父进程的,那么系统中第一个进程是复制谁的了?它是怎么产生的了?第一个进程有什么作用了?
我们知道windows中是通过CreateProcess这样的系统调用来实现创建进程的,那么windows实现的进程模型和Linux是一样的吗?如果不一样他们各自有什么差别,或者说各自有什么优缺点?其实我们在设计linux内核的时候也应该参照其他操作系统的内核的设计思想,就比如windows NT的机构就基于CMU 的MACH操作系统,基于消息传递的机制!

第三个小问:
进程调度的算法,你对现有的进程调度算法了解吗?如果让你在现有的调度算法中,你能不能做到让一个进程永远的在CPU上运行,如果能,你怎么做?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP