Chinaunix

标题: 一个进程可以分配多大的内存? [打印本页]

作者: congli    时间: 2006-03-25 15:37
标题: 一个进程可以分配多大的内存?
看<C专家编程>时,有一练习,程序如下:
  1.       1 #include <stdio.h>
  2.       2 #include <stdlib.h>
  3.       3
  4.       4 int main(){
  5.       5     int MB = 0;
  6.       6     while(malloc(1 << 20)) ++MB;
  7.       7     printf("Allocated %d MB total.\n", MB);
  8.       8 }
复制代码

运行该程序,看看进程可以分配多少的内存?

在默认内核下面,结果是:
Allocated 511 MB total.


先看看/usr/src/sys/i386/include/vmparam.h,其中定义的一个进程的最大数据段的大小MAXDSIZ就是512M。
/*
* Virtual memory related constants, all in bytes
*/
#define        MAXTSIZ                (128UL*1024*1024)        /* max text size */
#ifndef DFLDSIZ
#define        DFLDSIZ                (128UL*1024*1024)        /* initial data size limit */
#endif
#ifndef MAXDSIZ
#define        MAXDSIZ                (512UL*1024*1024)        /* max data size */
#endif
#ifndef        DFLSSIZ
#define        DFLSSIZ                (8UL*1024*1024)                /* initial stack size limit */
#endif
#ifndef        MAXSSIZ
#define        MAXSSIZ                (64UL*1024*1024)        /* max stack size */
#endif
#ifndef SGROWSIZ
#define SGROWSIZ        (128UL*1024)                /* amount to grow stack */
#endif


继续测试,根据handbook,在内核加入参数:
options MAXDSIZ="(1024*1024*1024)"
options DFLDSIZ="(1024*1024*1024)"

再运行该程序,结果是:
Allocated 1023 MB total.


接下来继续,把参数调大到2049看看: (感谢antijp指出先前的错误,现更正)
options MAXDSIZ="(2049ULL*1024*1024)"

结果是:
Allocated 2048 MB total.


PS:测试环境:FreeBSD 6.0-RELEASE,内存1GB.

后记:同一程序在Gentoo Linux上运行,结果是:
Allocated 3056 MB total.


感谢雨丝风片,antijp,gvim!欢迎大家讨论及指正

[ 本帖最后由 congli 于 2006-3-27 14:14 编辑 ]
作者: gvim    时间: 2006-03-25 15:41
options MAXDSIZ="(2048*1024*1024)"
options DFLDSIZ="(2048*1024*1024)"

把这个换成
options MAXDSIZ="(3221225472UL)"
options DFLDSIZ="(3221225472UL)"
试试呢。
看warning应该不是算法本身的限制吧,加上UL申请3G试试。
作者: congli    时间: 2006-03-25 15:48
好,马上试试.
作者: congli    时间: 2006-03-25 16:42
原帖由 gvim 于 2006-3-25 15:41 发表
options MAXDSIZ="(2048*1024*1024)"
options DFLDSIZ="(2048*1024*1024)"

把这个换成
options MAXDSIZ="(3221225472UL)"
options DFLDSIZ="(3221225472UL)"
试试 ...

能编译通过,但机器重启出问题.
init died (signal 0,  exit 1)
painc : Going nowhere without my init
cpuid = 0

最后机器15秒重启,重复...

[ 本帖最后由 congli 于 2006-3-27 22:44 编辑 ]
作者: antijp    时间: 2006-03-25 20:08
怀疑BSD之前先怀疑自己,我是看到你在freebsdchina上面的帖子以后才到这里来的。另外,贴FreeBSD的代码的时候把__FBSDID那段东西贴出来,否则有些东西fxr上面不好找(我现在一般除非要搜索,否则就直接在freebsd上面用cvsweb)
作者: congli    时间: 2006-03-25 20:34
己编辑.

[ 本帖最后由 congli 于 2006-3-26 00:21 编辑 ]
作者: antijp    时间: 2006-03-25 20:43
我在freebsdchina的回复你没有仔细看

需要2G的话,要用2048U(LL)? * 1024 * 1024
作者: congli    时间: 2006-03-25 20:45
原帖由 antijp 于 2006-3-25 20:43 发表
我在freebsdchina的回复你没有仔细看

需要2G的话,要用2048U(LL)? * 1024 * 1024

谢谢指点!
试试再说.
作者: gvim    时间: 2006-03-25 22:47
原帖由 antijp 于 2006-3-25 20:43 发表
我在freebsdchina的回复你没有仔细看

需要2G的话,要用2048U(LL)? * 1024 * 1024


他的意思是看FreeBSD最大可以分配多少空间。
限定最大数据空间为3G的情况下,实验结果是:相比Linux的3056 MB,freebsd不修改代码的情况下(也就是只调整config文件)启动时panic。

[ 本帖最后由 gvim 于 2006-3-25 22:49 编辑 ]
作者: zzbwang    时间: 2006-03-26 20:18
我也遇到了同样的问题,我在DELL2850服务器上安装了4GB内存,同时调整了/boot/loader.conf中的MAXDSIZ的值,发现当MAXDSIZ值设置到3GB以上时,服务器就不能启动。至今不知道什么原因。

楼主所作的试验我以前也做过,结果与楼主相同,原因不清楚。怀疑是BSD系统本身实现的问题。
作者: congli    时间: 2006-03-26 20:44
原帖由 zzbwang 于 2006-3-26 20:18 发表
我也遇到了同样的问题,我在DELL2850服务器上安装了4GB内存,同时调整了/boot/loader.conf中的MAXDSIZ的值,发现当MAXDSIZ值设置到3GB以上时,服务器就不能启动。至今不知道什么原因。

楼主所作的试验我以前也 ...

看过兄弟发的贴,
这个问题的确值得探讨.
而gvim兄弟在NetBSD上做的实验,将MAXDSIZ和DFLDSIZ为3G,编译通过,启动正常.

PS:现在只想知道为什么,而并不是评论那个好坏.
作者: szjungle    时间: 2006-03-26 20:56
能分得多大的内存,还应该跟机器的物理内存和交换分区大小有关。

NetBSD UVM FAQ 上有这么一条:

How much virtual memory do I have?

http://www.netbsd.org/Documentation/kernel/uvm.html#vm-how-big
作者: congli    时间: 2006-03-26 21:05
原帖由 szjungle 于 2006-3-26 20:56 发表
能分得多大的内存,还应该跟机器的物理内存和交换分区大小有关。

NetBSD UVM FAQ 上有这么一条:

How much virtual memory do I have?

[url]http://www.netbsd.org/Documentation/kernel/uvm.html#vm-ho ...

但zzbwang兄弟的机器好象是4GB的物理内存.
明天回公司搞台2G内存的机器来实验,不能再多了.
作者: fredrick    时间: 2006-03-26 23:55
如果只是分配内存的话,内核应该会使用一种“聪明”的办法来解决问题。 不妨试试分配内存之后往这些内存单元里写一点东西,那你可能会看到实际能分配的能力了。
作者: gvim    时间: 2006-03-27 09:24
原帖由 szjungle 于 2006-3-26 20:56 发表
能分得多大的内存,还应该跟机器的物理内存和交换分区大小有关。

NetBSD UVM FAQ 上有这么一条:

How much virtual memory do I have?

[url]http://www.netbsd.org/Documentation/kernel/uvm.html#vm-ho ...


我的机器是512M memoey+256M swap 可是申请的虚拟空间是2869M。
为什么会这样而不是FAQ上的样子,还需要看看代码。
作者: gvim    时间: 2006-03-27 09:26
原帖由 fredrick 于 2006-3-26 23:55 发表
如果只是分配内存的话,内核应该会使用一种“聪明”的办法来解决问题。 不妨试试分配内存之后往这些内存单元里写一点东西,那你可能会看到实际能分配的能力了。


实际能分配的,最大只能 (物理内存-内核所占大小)+swap空间大小。
我们实验的是虚拟分配的
作者: congli    时间: 2006-03-27 14:11
经过一翻折腾,终于找到了原因.感谢风雨^_^
默认情况下,系统会保留1GB空间(打开PAE,会保留2GB),所以导致MAXDSIZ=3GB启动时出现panic.
options MAXDSIZ="(3072ULL*1024*1024)"
options DFLDSIZ="(3072ULL*1024*1024)"

options KVA_PAGES="(192)"     # 实际大小是192*4=768MB,默认是256*4=1024MB


最后结果:
Allocated 3071 MB total.

呵~比linux还要多^_^

PS:虽然找到原因,修改后对性能是否影响请自行判定,此贴只属研究性质.
测试环境:FreeBSD i386 5.4-Release-p13 , 1GB内存.
作者: llzqq    时间: 2006-03-27 15:27
[root@bsd ~]#vi sh

#include <stdio.h>
#include <stdlib.h>

int main(){
        int MB = 0;
        while(malloc(1 << 20)) ++MB;
        printf("Allocated %d MB total.\n", MB);
}

# ./sh

./sh: line 4: syntax error near unexpected token `('
./sh: line 4: `int main(){'

怎么不行?

[ 本帖最后由 llzqq 于 2006-3-27 15:28 编辑 ]
作者: lunchan    时间: 2006-03-27 15:30
不是要main(void){}吧
作者: hongzjx    时间: 2006-03-27 15:51
呵呵,llzqq用shell来运行也可以吗?
作者: congli    时间: 2006-03-27 16:07
原帖由 hongzjx 于 2006-3-27 15:51 发表
呵呵,llzqq用shell来运行也可以吗?

呵~~需要编译.
作者: congli    时间: 2006-03-27 16:08
原帖由 llzqq 于 2006-3-27 15:27 发表
[root@bsd ~]#vi sh

#include <stdio.h>
#include <stdlib.h>

int main(){
        int MB = 0;
        while(malloc(1 << 20)) ++MB;
        printf("Allocated %d MB total ...

保存为m.c,
cc -o m m.c编译成m
./m
作者: llzqq    时间: 2006-03-27 16:48
原帖由 hongzjx 于 2006-3-27 15:51 发表
呵呵,llzqq用shell来运行也可以吗?



晕,没编译。
作者: gvim    时间: 2006-03-27 16:55
原帖由 congli 于 2006-3-27 14:11 发表
经过一翻折腾,终于找到了原因.感谢风雨^_^
默认情况下,系统会保留1GB空间(打开PAE,会保留2GB),所以导致MAXDSIZ=3GB启动时出现panic.


最后结果:

呵~比linux还要多^_^

PS:虽然找到原因,修改后对性能是否 ...


可是不应该啊。(我还没有进入内存管理部分,先把问题放在这里 )
疑问1:
为什么NetBSD不会crash。我看了相关文献和论文,FreeBSD的vm和NetBSD的uvm 策略差别不大。
疑问2:
"默认情况下,系统会保留1GB空间"这是保留的内核空间,但是进程可以用的最大空间还是3G,修改KVA_PAGES只是减小了内核保留的虚拟空间。比喻下应该是拆东墙补西墙的感觉
作者: 雨丝风片    时间: 2006-03-27 17:00
谈谈我对这个问题的看法。

在32位机器的4GB的地址空间中,高端的1GB是缺省留给内核使用的,低端的大致3GB的空间则留给进程自己使用。我们知道,对于一个传统的unix进程的内存布局而言,低端是text段,然后是data段,然后是向上生长的heap,位于高端的则是向下生长的stack。由于data和heap的大小在FreeBSD里是统一规划的,所以在此不做严格区分。

但对于现在的系统而言,heap和stack之间并非一马平川,这里面还有一部分是给mmap预留的空间。如下图所示,左边表示的是FreeBSD进程的内存布局,右边则是Linux进程的内存布局。

我们可以看到,FreeBSD进程的heap向上生长的极限并不是stack的顶部,而是mmap区域的底部。图中用红线表示。这个界限就是前面所说的MAXDSIZ参数的意义,也就是说,data段最大只能到达此处。和stack碰头的任务就交给mmap了,事实上,mmap区域向上生长的极限就是stack向下生长的极限,也就是由MAXSSIZ参数对应的stack下限地址。因此,一个系统中有多少空间用于mmap就由MAXDSIZ和MAXSSIZ两个参数限定了。

在前面的试验中,我们逐步增大MAXDSIZ,实际上就是在逐步压缩mmap的生存空间,直至系统中那些依赖于mmap的程序出现问题为止。

再来看看Linux进程的内存布局。它的mmap区域改成了从顶端向下生长, 于是,原来stack和heap碰头的事情就交给了mmap来做了。这样的效果就是如果mmap没干过什么的话,heap就可以一直生长到stack那儿!我认为,这也就是为什么同样的程序,在Linux上不做任何修改的情况下就能让heap长到3056MB的原因。

大家继续。。。


作者: congli    时间: 2006-03-27 17:00
原帖由 gvim 于 2006-3-27 16:55 发表


可是不应该啊。(我还没有进入内存管理部分,先把问题放在这里 )
疑问1:
为什么NetBSD不会crash。我看了相关文献和论文,FreeBSD的vm和NetBSD的uvm 策略差别不大。
疑问2:
"默认情况下,系统会保留 ...

的确是拆东墙补西墙的感觉

[ 本帖最后由 congli 于 2006-3-27 22:50 编辑 ]
作者: 雨丝风片    时间: 2006-03-27 17:04
原帖由 gvim 于 2006-3-27 16:55 发表
默认情况下,系统会保留1GB空间"这是保留的内核空间,但是进程可以用的最大空间还是3G,修改KVA_PAGES只是减小了内核保留的虚拟空间。比喻下应该是拆东墙补西墙的感觉 ...


偶现在暂时把怀疑的焦点聚集在了mmap区域身上,内核空间的“让步”也正是为了疏缓一下由于增大heap而带给mmap的生存压力。
作者: gvim    时间: 2006-03-27 17:05
原帖由 雨丝风片 于 2006-3-27 17:00 发表
谈谈我对这个问题的看法。

在32位机器的4GB的地址空间中,高端的1GB是缺省留给内核使用的,低端的大致3GB的空间则留给进程自己使用。我们知道,对于一个传统的unix进程的内存布局而言,低端是text段,然后是 ...


我昨天试了下(NB)用的-static编译静态程序,运行程序可以多分得1M的虚拟空间。我估计mmap空间不会保留的那么大,以至于我困惑于实际分得的2869M和3072M还有很大的差距。(当然3072还需要去除text segment等东西。我实验的情况大约占了虚拟空间16M左右。)
作者: 雨丝风片    时间: 2006-03-27 17:07
原帖由 gvim 于 2006-3-27 17:05 发表


我昨天试了下(NB)用的-static编译静态程序,运行程序可以多分得1M的虚拟空间。我估计mmap空间不会保留的那么大,以至于我困惑于实际分得的2869M和3072M还有很大的差距。(当然3072还需要去除text segment等东西 ...



mmap保留多大是由MAXDSIZ决定的,data段不要的都给mmap,
作者: gvim    时间: 2006-03-27 17:12
原帖由 雨丝风片 于 2006-3-27 17:07 发表



mmap保留多大是由MAXDSIZ决定的,data段不要的都给mmap,


内存分配是lazy allocation的吧。现在情况是data段都需要,难道系统需要为每个进程保留200M左右的mmap空间?不合理吧
作者: 雨丝风片    时间: 2006-03-27 17:16
原帖由 gvim 于 2006-3-27 17:12 发表


内存分配是lazy allocation的吧。现在情况是data段都需要,难道系统需要为每个进程保留200M左右的mmap空间?不合理吧


那MAXDSIZ拿来做什么?

只是系统默认情况下heap小(几百M),mmap大(上G)而已。

Linux正是出于和你同样的疑问才把mmap的生长方向调了个个儿的!

[ 本帖最后由 雨丝风片 于 2006-3-27 17:21 编辑 ]
作者: gvim    时间: 2006-03-27 17:25
我理解你的意思。我的意思是将MAXDSIZ=3*1024*1024*1024的时候,也就是最大数据va大小是3G了。并且我也不打算使用mmap这个东西(比如1楼的小程序)。
那么,首先就FB来说,它就panic了。
就NB来说,可以分配2869的空间。stack size,text size都很小,stack没有修改的情况下大约是2M,等于DFLSSIZ大小。也就是说,中间还有大约200M左右分配不出来了。
我的疑问在于,保留给mmap需要这么大吗?而且在该程序里面并没有对mmap空间的申请阿。
作者: 雨丝风片    时间: 2006-03-27 17:29
原帖由 gvim 于 2006-3-27 17:25 发表
我理解你的意思。我的意思是将MAXDSIZ=3*1024*1024*1024的时候,也就是最大数据va大小是3G了。并且我也不打算使用mmap这个东西(比如1楼的小程序)。
那么,首先就FB来说,它就panic了。
就NB来说,可以分配28 ...


我明白你的意思了,你是怀疑这分不出来的200多M是给mmap了?

那你就还没有明白我的另外一层意思,mmap的空间是由MAXDSIZ决定的,heap增大,mmap就缩小,直至为0,不会有一个最小值的。

你还没把地址空间最下边那128M的未映射区域算进去吧?
作者: gvim    时间: 2006-03-27 17:29
congli兄在gentoo上的实验结果是 3056 MB 距3G只有16M空间。这16M包含了text,stack,(或许还有的mmap),因此我想BSD不会硬性的保留200M左右出来做mmap的最小尺寸吧。
作者: gvim    时间: 2006-03-27 17:35
原帖由 雨丝风片 于 2006-3-27 17:29 发表

你还没把地址空间最下边那128M的未映射区域算进去吧?


?我怎么没有看见有这个提法?我只知道0G开始分配一个页面之后的地方开始分配text
不过128M也有点吃惊
老大在哪里看见的?我去看一看。免得继续在论坛上开黄腔
作者: 雨丝风片    时间: 2006-03-27 17:41
原帖由 gvim 于 2006-3-27 17:29 发表
congli兄在gentoo上的实验结果是 3056 MB 距3G只有16M空间。这16M包含了text,stack,(或许还有的mmap),因此我想BSD不会硬性的保留200M左右出来做mmap的最小尺寸吧。


我现在只能从大的方面来区别FreeBSD和Linux进程地址空间布局的不同,但还不清楚Linux具体是怎么实现的。从我看到的资料来看,Linux的heap可以一直向上越过stack的最大边界,直接抵达stack的当前使用边界。暂时还没有进一步的资料,只有先存疑了。

我也认为BSD没有这个硬性的mmap最小空间,而且暂时怀疑将数据段逼近3G之后出现的问题是和mmap没有生存空间有关的,这很可能导致系统无法正常工作。

[ 本帖最后由 雨丝风片 于 2006-3-27 18:04 编辑 ]
作者: 雨丝风片    时间: 2006-03-27 17:47
原帖由 gvim 于 2006-3-27 17:35 发表


?我怎么没有看见有这个提法?我只知道0G开始分配一个页面之后的地方开始分配text
不过128M也有点吃惊
老大在哪里看见的?我去看一看。免得继续在论坛上开黄腔


是elf格式固定从0x8000000开始加载text段的。
作者: gvim    时间: 2006-03-27 17:59
原帖由 雨丝风片 于 2006-3-27 17:47 发表


是elf格式固定从0x8000000开始加载text段的。


哦,对喉,只想到系统保留的去了,忘了这个......
恩,不过还有疑问,在看看先
作者: llzqq    时间: 2006-03-27 18:14
在openbsd-3.8上试了试:

[root@bsd ~]#./m
Allocated 1022 MB total.

在OPENBSD上怎么调大呢,没看到那里可以调节。

[ 本帖最后由 llzqq 于 2006-3-27 18:15 编辑 ]
作者: gvim    时间: 2006-03-27 18:22
原帖由 llzqq 于 2006-3-27 18:14 发表
在openbsd-3.8上试了试:

[root@bsd ~]#./m
Allocated 1022 MB total.

在OPENBSD上怎么调大呢,没看到那里可以调节。


NB和FB都可以在config里面加options MAXDSIZ来调节方法在congli兄的第一张帖子里那样,我对OB没有碰过,老大试试。
作者: jjdeng    时间: 2006-03-27 19:27
当年我看<<C专家编程>>的时候怎么就没在机器上调调呢
哈哈 落伍了
作者: 雨丝风片    时间: 2006-03-27 19:31
原帖由 jjdeng 于 2006-3-27 19:27 发表
当年我看<<C专家编程>>的时候怎么就没在机器上调调呢
哈哈 落伍了


看似简单的问题也能挖出这么多水来,
作者: 无倦    时间: 2006-03-27 20:47
呵呵,有个疑问,用 while(malloc(1024)) 来试了一下, 程序把所有的内存和SWAP耗尽后就死了,malloc(1 <<20)好象没占用内存就运行完毕的?
作者: congli    时间: 2006-03-27 22:55
原帖由 llzqq 于 2006-3-27 18:14 发表
在openbsd-3.8上试了试:

[root@bsd ~]#./m
Allocated 1022 MB total.

在OPENBSD上怎么调大呢,没看到那里可以调节。

估计是调整过.
公司的那台OB结果是:Allocated 511 MB total.
作者: 雨丝风片    时间: 2006-03-28 07:54
原帖由 无倦 于 2006-3-27 20:47 发表
呵呵,有个疑问,用 while(malloc(1024)) 来试了一下, 程序把所有的内存和SWAP耗尽后就死了,malloc(1 <<20)好象没占用内存就运行完毕的?


请问你用的是什么系统?“程序把所有的内存和SWAP耗尽后就死了”的具体所指为何?
作者: llzqq    时间: 2006-03-28 08:25
原帖由 congli 于 2006-3-27 22:55 发表

估计是调整过.
公司的那台OB结果是:Allocated 511 MB total.


偶在编译内核时修改了:

maxusers           64


其他没作设置,就是这个结果了,难道OPENBSD可以这样调节程序最大使用的内存?
作者: congli    时间: 2006-03-28 09:52
原帖由 llzqq 于 2006-3-28 08:25 发表


偶在编译内核时修改了:

maxusers           64


其他没作设置,就是这个结果了,难道OPENBSD可以这样调节程序最大使用的内存?

哦,明白了,
管理员跟普通用户不同;
root:Allocated 1022 MB total.
普通用户:Allocated 511 MB total.
作者: gvim    时间: 2006-03-28 10:15
原帖由 无倦 于 2006-3-27 20:47 发表
呵呵,有个疑问,用 while(malloc(1024)) 来试了一下, 程序把所有的内存和SWAP耗尽后就死了,malloc(1 <<20)好象没占用内存就运行完毕的?


我昨天在NetBSD上试了malloc(1024),没有出现你说的现象。
作者: Alligator27    时间: 2006-03-28 10:53
原帖由 congli 于 2006-3-28 09:52 发表

哦,明白了,
管理员跟普通用户不同;
root:Allocated 1022 MB total.
普通用户:Allocated 511 MB total.


是因为 ulimit 设置不一样?
作者: congli    时间: 2006-03-28 11:01
原帖由 Alligator27 于 2006-3-28 10:53 发表


是因为 ulimit 设置不一样?

惭愧,这个还没有研究过
作者: Alligator27    时间: 2006-03-28 11:13
补充一句:

PT2 malloc (大多数Linux): 如果size>256KB, 内存是mmap()得来的. 否则是用sbrk(). 这个值可编程修改.
Debian/Novell 的Hoard是64KB.
作者: 雨丝风片    时间: 2006-03-28 14:44
原帖由 Alligator27 于 2006-3-28 11:13 发表
补充一句:

PT2 malloc (大多数Linux): 如果size>256KB, 内存是mmap()得来的. 否则是用sbrk(). 这个值可编程修改.
Debian/Novell 的Hoard是64KB.



FreeBSD的malloc仍然是基于brk/sbrk的,仅有一个用于管理的页面目录是用mmap分配的。
作者: congli    时间: 2006-03-28 16:08
继续折腾,不过这次是KVA_PAGES保持系统默认,只修改MAXDISZ及DFLDSIZ,并不断增加,看看其"极限"是多少.
经过不断的折腾,向大家提供一些"有趣"的数据:
下面数据每次都是重新编译内核,重启后的数据.

测试环境:FreeBSD i386 5.4-Release-p13, RAM 1278MB.(5.4跟6.0的有点不一样)

1."2912"
options MAXDSIZ="(2912ULL*1024*1024)"
options DFLDSIZ="(2912ULL*1024*1024)"


结果1:
Allocated 2911 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2912M
max stack segment : max = 64M


2."2920"
options MAXDSIZ="(2920ULL*1024*1024)"
options DFLDSIZ="(2920ULL*1024*1024)"


结果1:
Allocated 2919 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2920M
max stack segment : max = 64M


结果3:(make kernel)
virtual memory exhausted: Cannot allocate memory



3."2928"
options MAXDSIZ="(2928ULL*1024*1024)"
options DFLDSIZ="(2928ULL*1024*1024)"


结果1:
Allocated 2927 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2928M
max stack segment : max = 64M


结果3:(make kernel)
virtual memory exhausted: Cannot allocate memory


4."2934"
options MAXDSIZ="(2934ULL*1024*1024)"
options DFLDSIZ="(2934ULL*1024*1024)"


结果1:
Allocated 1531 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2934M
max stack segment : max = 64M


结果3:(启动过程中,开始有服务出错)
Initial i386 initialization:.
Additional ABI support: linux/compat/linux/sbin/ldconfig: Cannot mmap file /lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb_cxx-4.0.so.

.
Starting cron.
Local package initialization:Starting compat4x.
Starting apache22.
httpd: Syntax error on line 83 of /usr/local/etc/apache22/httpd.conf: Cannot load /usr/local/libexec/apache22/mod_ssl.so into server: /lib/libcrypto.so.3: mmap
of entire address space failed: Cannot allocate memory
cups: started scheduler.
Starting cvs pserver chroot wrapper: cvsd.
Starting cvsupd.

/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory



结果4:(make kernel)
--------------------------------------------------------------
>>> stage 2.3: build tools
--------------------------------------------------------------
cd /usr/obj/usr/src/sys/PF;  MAKESRCPATH=/usr/src/sys/dev/aic7xxx/aicasm  make -DNO_CPU_CFLAGS -f /usr/src/sys/dev/aic7xxx/aicasm/Makefile
Warning: Object directory not changed from original /usr/obj/usr/src/sys/PF
cc -O -pipe -nostdinc -I/usr/include -I. -I/usr/src/sys/dev/aic7xxx/aicasm  -c /usr/src/sys/dev/aic7xxx/aicasm/aicasm.c
virtual memory exhausted: Cannot allocate memory
*** Error code 1


5."2935"
options MAXDSIZ="(2935ULL*1024*1024)"
options DFLDSIZ="(2935ULL*1024*1024)"


结果1:
Allocated 1195 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2935M
max stack segment : max = 64M


结果3:(dmesg)
Initial i386 initialization:.
Additional ABI support: linux/compat/linux/sbin/ldconfig: Cannot mmap file /lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb_cxx-4.0.so.

.
Starting cron.
Local package initialization:Starting compat4x.
Starting apache22.
httpd: Syntax error on line 83 of /usr/local/etc/apache22/httpd.conf: Cannot load /usr/local/libexec/apache22/mod_ssl.so into server: /usr/lib/libssl.so.3: mmap of entire address space failed: Cannot allocate memory
cups: started scheduler.
Starting cvs pserver chroot wrapper: cvsd.
Starting cvsupd.

/libexec/ld-elf.so.1: /usr/local/lib/libiconv.so.3: mmap of entire address space failed: Cannot allocate memory



结果4:(make kernel)
--------------------------------------------------------------
>>> stage 2.3: build tools
--------------------------------------------------------------
cd /usr/obj/usr/src/sys/PF;  MAKESRCPATH=/usr/src/sys/dev/aic7xxx/aicasm  make -DNO_CPU_CFLAGS -f /usr/src/sys/dev/aic7xxx/aicasm/Makefile
Warning: Object directory not changed from original /usr/obj/usr/src/sys/PF
cc -O -pipe -nostdinc -I/usr/include -I. -I/usr/src/sys/dev/aic7xxx/aicasm  -c /usr/src/sys/dev/aic7xxx/aicasm/aicasm.c
virtual memory exhausted: Cannot allocate memory
*** Error code 1



6."2936"
options MAXDSIZ="(2936ULL*1024*1024)"
options DFLDSIZ="(2936ULL*1024*1024)"


结果1:
Allocated 859 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2936M
max stack segment : max = 64M


结果3:(dmesg)
Initial i386 initialization:.
Additional ABI support: linux/compat/linux/sbin/ldconfig: Cannot mmap file /lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb_cxx-4.0.so.

.
Starting cron.
Local package initialization:Starting compat4x.
Starting apache22.
/libexec/ld-elf.so.1: /usr/local/lib/libdb-4.2.so.2: mmap of entire address space failed: Cannot allocate memory
cups: started scheduler.
Starting cvs pserver chroot wrapper: cvsd.
Starting cvsupd.

Starting SAMBA: removing stale tdbs :
/var/db/samba/messages.tdb
/var/db/samba/unexpected.tdb
Starting nmbd.
/libexec/ld-elf.so.1: /lib/libcrypto.so.3: mmap of entire address space failed:
Cannot allocate memory
Starting smbd.
/libexec/ld-elf.so.1: /usr/local/lib/compat/pkg/libgnutls.so.12: mmap of entire
address space failed: Cannot allocate memory
.


结果4:(make kernel)
--------------------------------------------------------------
>>> stage 2.3: build tools
--------------------------------------------------------------
cd /usr/obj/usr/src/sys/PF;  MAKESRCPATH=/usr/src/sys/dev/aic7xxx/aicasm  make -DNO_CPU_CFLAGS -f /usr/src/sys/dev/aic7xxx/aicasm/Makefile
Warning: Object directory not changed from original /usr/obj/usr/src/sys/PF
cc -O -pipe -nostdinc -I/usr/include -I. -I/usr/src/sys/dev/aic7xxx/aicasm  -c /usr/src/sys/dev/aic7xxx/aicasm/aicasm.c
virtual memory exhausted: Cannot allocate memory
*** Error code 1


7."2937"
options MAXDSIZ="(2937ULL*1024*1024)"
options DFLDSIZ="(2937ULL*1024*1024)"



结果1:
Allocated 523 MB total.


结果2:
total address space : max = 4095M
max data segment : max = 2937M
max stack segment : max = 64M


结果3:(dmesg)
Starting sshd.
/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory
/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory
/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory
Initial i386 initialization:.
Additional ABI support: linuxem0: Link is up 100 Mbps Full Duplex
/compat/linux/sbin/ldconfig: Cannot mmap file /lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb-4.0.so.

/compat/linux/sbin/ldconfig: Cannot mmap file /usr/lib/libdb_cxx-4.0.so.

.
Starting cron.
Local package initialization:Starting compat4x.
Starting apache22.
/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory
/libexec/ld-elf.so.1: /usr/local/lib/libiconv.so.3: mmap of entire address space failed: Cannot allocate memory
cups: unable to start scheduler.
Starting cvs pserver chroot wrapper: cvsd.
Starting cvsupd.

Starting SAMBA: removing stale tdbs :
Starting nmbd.
/libexec/ld-elf.so.1: /lib/libc.so.5: mmap of entire address space failed: Cannot allocate memory
Starting smbd.
ELF interpreter /libexec/ld-elf.so.1 not found
Abort trap
.


结果4:(make kernel)
--------------------------------------------------------------
>>> stage 2.3: build tools
--------------------------------------------------------------
cd /usr/obj/usr/src/sys/PF;  MAKESRCPATH=/usr/src/sys/dev/aic7xxx/aicasm  make -DNO_CPU_CFLAGS -f /usr/src/sys/dev/aic7xxx/aicasm/Makefile
Warning: Object directory not changed from original /usr/obj/usr/src/sys/PF
cc -O -pipe -nostdinc -I/usr/include -I. -I/usr/src/sys/dev/aic7xxx/aicasm  -c /usr/src/sys/dev/aic7xxx/aicasm/aicasm.c
virtual memory exhausted: Cannot allocate memory
*** Error code 1


结果5:(系统启动后,ttyv0显示该信息)
Mar 28 13:09:41 FreeBSD init: getty repeating too quickly on port /dev/ttyv8, sleeping 30 secs



8."2938"
options MAXDSIZ="(2938ULL*1024*1024)"
options DFLDSIZ="(2938ULL*1024*1024)"


结果:
能启动系统,出现login提示符,输入用户及密码,显示motd信息后,马上自动退出,返回login提示符.返回login提示前屏幕显示:/libexec/ld-elf.so.1:/lib/libc.so.5:mmap of entire address space faild:Cannot allocate memory


9."2939"
options MAXDSIZ="(2939ULL*1024*1024)"
options DFLDSIZ="(2939ULL*1024*1024)"


结果:
进入单用户模式,但不能登录,屏幕显示:/libexec/ld-elf.so.1:/lib/libc.so.5:mmap of entire address space faild:Cannot allocate memory


10."2940"
options MAXDSIZ="(2940ULL*1024*1024)"
options DFLDSIZ="(2940ULL*1024*1024)"


结果:panic
init died (signal 0,  exit 1)
panic : Going nowhere without my init


P.S.
结果1小程序:
  1.       1 #include <stdio.h>
  2.       2 #include <stdlib.h>
  3.       3
  4.       4 int main(){
  5.       5     int MB = 0;
  6.       6     while(malloc(1 << 20)) ++MB;
  7.       7     printf("Allocated %d MB total.\n", MB);
  8.       8 }
复制代码

结果2小程序:
  1.       1 #include <sys/types.h>
  2.       2 #include <sys/time.h>
  3.       3 #include <sys/resource.h>
  4.       4
  5.       5 int main(void){
  6.       6
  7.       7     struct rlimit limit;
  8.       8     if (getrlimit(RLIMIT_AS, &limit) == 0)
  9.       9         printf("total address space : max = %uM\n", ((unsigned int)limit.rlim_max)/(1024*1024));
  10.      10
  11.      11     if (getrlimit(RLIMIT_DATA, &limit) == 0)
  12.      12         printf("max data segment : max = %uM\n", ((unsigned int)limit.rlim_max)/(1024*1024));
  13.      13
  14.      14     if (getrlimit(RLIMIT_STACK, &limit) == 0)
  15.      15         printf("max stack segment : max = %uM\n", ((unsigned int)limit.rlim_max)/(1024*1024));
  16.      16
  17.      17 }
复制代码

[ 本帖最后由 congli 于 2006-3-28 21:07 编辑 ]
作者: congli    时间: 2006-03-28 16:27
从"2912"启动,虽然可以make kernel,可以进入gnome2,但打不开firefox,没有任何出错信息,就是打不开.
作者: 无倦    时间: 2006-03-28 16:43
原帖由 gvim 于 2006-3-28 10:15 发表


我昨天在NetBSD上试了malloc(1024),没有出现你说的现象。



呵呵,我是在redhat 4.1 下, freebsd没有测试机,不敢在生产的机上搞, 程序占完所有内存和swap后就被操作系统自动KILL了, malloc(1 <<20)就不会出现这种情况
作者: 雨丝风片    时间: 2006-03-28 17:14
原帖由 congli 于 2006-3-28 16:08 发表
继续折腾,不过这次是KVA_PAGES保持系统默认,只修改MAXDISZ及DFLDSIZ,并不断增加,看看其"极限"是多少.
经过不断的折腾,向大家提供一些"有趣"的数据:
下面数据每次都是重新编译内核,重启后的 ...



辛苦辛苦!

从试验结果来看,的确是随着数据段的逐渐增长,mmap的生存空间被不断压缩,使得基于mmap的各种库陆续出现分配不到空间的情况,最终导致系统启动失败。

另外,在2934M之前,实际malloc得到的空间是随着数据段上限的增长而增长的,但从2934M开始,实际malloc得到的空间却呈急速下降趋势。这种下降是有规律的,分析数字可知,mmap的生存空间每缩小1M,实际malloc得到的空间就减少336M。这个现象可以从FreeBSD的malloc的实现方式上来解释。

我在前面已经提到,FreeBSD的malloc仍然是基于brk/sbrk的,只不过它和内核之间的内存交易的粒度是页面而已。malloc会专门为它所管理的页面维护一个页面目录的结构,这个结构的空间就是用mmap生成的。这个页面目录空间对于整个malloc管理的空间而言可谓是牵一发而动全身,这儿少分配了一点,就会导致malloc得到的空间少很多。

在前面的试验中,我们不断地执行malloc操作,相应地,malloc也会逐渐通过mmap来扩展存放页面目录的空间。随着我们不断地调整内核参数,mmap的生存空间被逐步压缩,总有一个时刻会导致malloc扩展页面目录空间失败,于是就会出现实际malloc得到的内存急剧减少的现象。随着mmap生存空间的进一步压缩,可由mmap分配给页面目录的空间进一步减少,于是实际malloc得到的内存也就进一步减少了。无论是从试验数据来说,还是从前面的分析来说,这种因mmap分配页面目录空间失败而导致的实际malloc得到的空间减少的现象都呈现出一种线性的关系。至于336这个具体数字的解释,在进一步阅读malloc源代码之后应该就可以给出了。

作者: congli    时间: 2006-03-28 17:28
原帖由 雨丝风片 于 2006-3-28 17:14 发表



辛苦辛苦!

从试验结果来看,的确是随着数据段的逐渐增长,mmap的生存空间被不断压缩,使得基于mmap的各种库陆续出现分配不到空间的情况,最终导致系统启动失败。

另外,在2934M之前,实际mall ...

呵~~
PFPF
作者: gvim    时间: 2006-03-28 18:26
辛苦congli老大了。风雨的解释我还要再想想 ~_~

恩,过段时间看看NetBSD的UVM和FreeBSD的VM到底有什么不同。
NetBSD修改MAXDSIZ之后,至少可以启动,可以正常运行程序。而且,好像,我后面编译内核时使用的内核就已经将MAXDSIZ调整到3*1024*1024*1024之后的值。(我记得安装之后没有恢复过)
从这个单方面说,难道UVM模型真比FB采用的模型优秀些?
呵呵,有意思
作者: 雨丝风片    时间: 2006-03-28 19:05
原帖由 gvim 于 2006-3-28 18:26 发表
恩,过段时间看看NetBSD的UVM和FreeBSD的VM到底有什么不同。
NetBSD修改MAXDSIZ之后,至少可以启动,可以正常运行程序。而且,好像,我后面编译内核时使用的内核就已经将MAXDSIZ调整到3*1024*1024*1024之后的值。(我记得安装之后没有恢复过)
从这个单方面说,难道UVM模型真比FB采用的模型优秀些?
呵呵,有意思


我觉得,从目前来看这里还涉及不到NB的UVM和FB的VM孰优孰劣的问题,而仅仅是一个进程的地址空间如何分布以及malloc如何实现的问题。NetBSD的malloc和FreeBSD的malloc出自一人,所以,两者表现差异的原因可能就是进程的地址空间分布了。

我在前面曾经怀疑过NetBSD的进程地址空间布局和Linux是一样的,即mmap空间从高向低长。今天查了一下NetBSD的文档,证实了我的想法:
【NetBSD Documentation: UVM, the new Virtual Memory system】
What is ``top down'' memory allocation?
This rearranges mmap(2)'ed memory allocations that don't request a specific address such that they start directly below the stack and work from the top down, instead of from the middle upwards. By doing this, the area of space reserved for heap growth and the area of space reserved for mmap(2)'ed allocations are merged, meaning that the heap can grow larger, or a process can mmap more or larger objects. The kernel still uses the traditional ``bottom up'' scheme for its internal memory management.


这里说的很清楚,NetBSD的mmap空间现在已经改成了从堆栈下面向下生长,而不是像原来那样从中间向上生长了。而且这里还点明了这样做的目的就是让heap或mmap有更大的生存空间。只不过内核仍然使用的是传统的自底向上的内存管理方案。

联系到我在前面帖子里画出的FreeBSD和Linux进程地址空间布局的示意图,就可以看出NetBSD的内存布局是和Linux一样的,Linux能够直接malloc到3G多,NetBSD自然也可以。

[ 本帖最后由 雨丝风片 于 2006-3-28 19:18 编辑 ]
作者: Alligator27    时间: 2006-03-28 22:20
malloc 是在用户空间, 不会管理页面. 那是kernel的事.

我试了一下, Linux/AIX的mmap是由下向上的, Solaris/HP-UX与BSDs相似, 由上向下. (BSDs我没有机器试, 以上面贴的Document说.)

我的测试程序及结果如下.



  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <errno.h>
  5. #include <sys/mman.h>

  6. int main(void)
  7. {
  8.     char *p;

  9.     size_t pgsize = ::sysconf(_SC_PAGE_SIZE);
  10.     size_t size = 2*pgsize;

  11.     for(int i=0; i<10; i++)
  12.     {
  13.                 p = (char*) ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  14.                 if (!p)
  15.                 {
  16.                         fprintf(stderr, "Failed: mmap size=%ld", size);
  17.                         exit(errno);
  18.                 }
  19.                 printf("p(%d) = 0x%lx\n", i, p);
  20.         }

  21.     return 0;
  22. }

复制代码



  1. ======== RedHat AS 3 / x86_64 ==========
  2. p(0) = 0x2a9566d000
  3. p(1) = 0x2a95670000
  4. p(2) = 0x2a95672000
  5. p(3) = 0x2a95674000
  6. p(4) = 0x2a95676000
  7. p(5) = 0x2a95678000
  8. p(6) = 0x2a9567a000
  9. p(7) = 0x2a9567c000
  10. p(8) = 0x2a95d2c000
  11. p(9) = 0x2a95d2e000
  12. ======== Solaris / sparc ==========
  13. p(0) = 0xff160000
  14. p(1) = 0xff030000
  15. p(2) = 0xff020000
  16. p(3) = 0xff010000
  17. p(4) = 0xff000000
  18. p(5) = 0xfeff0000
  19. p(6) = 0xfefe0000
  20. p(7) = 0xfefd0000
  21. p(8) = 0xfefc0000
  22. p(9) = 0xfefb0000
  23. ======== HP-UX / IA64 ==========
  24. p(0) = 0x7efb4000
  25. p(1) = 0x7efb2000
  26. p(2) = 0x7efb0000
  27. p(3) = 0x7efae000
  28. p(4) = 0x7efac000
  29. p(5) = 0x7efaa000
  30. p(6) = 0x7efa8000
  31. p(7) = 0x7efa6000
  32. p(8) = 0x7efa4000
  33. p(9) = 0x7efa2000
  34. ======== AIX / PPC ==========
  35. p(0) = 0x30000000
  36. p(1) = 0x30002000
  37. p(2) = 0x30004000
  38. p(3) = 0x30006000
  39. p(4) = 0x30008000
  40. p(5) = 0x3000a000
  41. p(6) = 0x3000c000
  42. p(7) = 0x3000e000
  43. p(8) = 0x30010000
  44. p(9) = 0x30012000
复制代码

作者: 雨丝风片    时间: 2006-03-29 08:14
原帖由 Alligator27 于 2006-3-28 22:20 发表
malloc 是在用户空间, 不会管理页面. 那是kernel的事.

呵呵,是我前面没有说清楚。malloc的“页面”和我们通常意义上的页面不是一回事。前已述及,malloc和内核打交道的单位就是页面,也就是说,它与内核之间的内存交易是以页面为单位的。

为了避免经常性地调用sbrk,malloc需要自己维护它所分配的所有内存页面。如果在它自己维护的这个内存“池”里面存在能够满足要求的空闲空间,那它就没必要去调用sbrk。为了实现这个目的,malloc得先把自己名下的这些页面“组织”起来。最简单的方法就是链表,但是链表指针本身会占用页面内部的空间,这常常会造成更大的内存浪费。于是FreeBSD的malloc就把这些页面的管理信息单独找个地方来存放,也就是所谓的“页面目录”,通过这个页面目录来实现malloc页面的查找、添加、删除、合并等操作。malloc名下的每一个页面都会对应这个页面目录中的一个条目,如果因为空间原因无法生成相应的页面目录条目,对应的内存页面的分配自然也会失败。

在前面的实验中,当数据段上限增大到2934M之后,实际malloc得到的空间急速下降,1531、1195、859、523,非常整齐的等差数列。mmap的生存空间每减少1M,实际malloc的内存就减少336M,这说明,在mmap和malloc之间存在着一个非常规则的线性关系。而FreeBSD的malloc和mmap的唯一关系就是“页面目录”。我们可以看到,在上述情况下,实际malloc得到的内存离数据段的上限还差得很远,但由于mmap的生存空间已经太小,无法扩展页面目录来存放新malloc到的内存页面的管理信息,于是导致malloc失败。

原帖由 Alligator27 于 2006-3-28 22:20 发表
我试了一下, Linux/AIX的mmap是由下向上的, Solaris/HP-UX与BSDs相似, 由上向下. (BSDs我没有机器试, 以上面贴的Document说.)


不知道你实验的Linux的内核版本是多少?我之所以说Linux的mmap是从栈顶向下生长的,依据见下面的链接。看日期是2004年6月30日的邮件。从邮件内容来看,Linux的mmap原来也是从下向上生长的。我对于Linux的版本和代码不熟,目前还不能确定是否有、以及从哪一个版本开始的mmap是遵循从上到下规则的。

【Reorganizing the address space】

另外,根据我们的实验和相关文档资料,各种BSD的mmap生长方向也是不一样的。FreeBSD从下到上,NetBSD从上到下。可参考我前面画出的FreeBSD和Linux进程地址空间的布局示意图。

[ 本帖最后由 雨丝风片 于 2006-3-29 08:19 编辑 ]
作者: 雨丝风片    时间: 2006-03-29 08:27
我在网上查了一下Linux 2.6.16版本的mmap.c,其中有这么一段:

  1. 1230 /*
  2. 1231  * This mmap-allocator allocates new areas top-down from below the
  3. 1232  * stack's low limit (the base):
  4. 1233  */
  5. 1234 #ifndef HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
  6. 1235 unsigned long
  7. 1236 arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
  8. 1237                           const unsigned long len, const unsigned long pgoff,
  9. 1238                           const unsigned long flags)
  10. 1239 {
  11. 1240         struct vm_area_struct *vma;
  12. 1241         struct mm_struct *mm = current->mm;
  13. 1242         unsigned long addr = addr0;
  14. ......
复制代码


我想,这应该就是Linux(至少是这个版本)的mmap从上向下生长的证据吧?

[ 本帖最后由 雨丝风片 于 2006-3-29 08:28 编辑 ]
作者: 雨丝风片    时间: 2006-03-29 08:32
继续搜索,在Linux 2.4.22的mmap.c中没有上面提到的这个函数。因此,mmap的方向逆转应该出现在2.4和2.6中间。
作者: congli    时间: 2006-03-29 08:44
在前面的实验中,当数据段上限增大到2934M之后,实际malloc得到的空间急速下降,1531、1195、859、523,非常整齐的等差数列。

估计2932及2933用malloc得到的空间已经开始下降.
作者: 雨丝风片    时间: 2006-03-29 09:13
原帖由 congli 于 2006-3-29 08:44 发表

估计2932及2933用malloc得到的空间已经开始下降.


黑色数字为实测数据,蓝色数字为猜想数据。。。
2930 - 2875
2931 - 2539
2932 - 2203
2933 - 1867

2934 - 1531
2935 - 1195
2936 - 859
2937 - 523
2938 - 187

我觉得,这个递减过程从哪儿开始、到哪儿结束并不重要,这应该是和当时的地址空间使用情况相关的。重要的是这里面体现出来的线性关系。扩大数据段上限本来是想扩展heap,压缩mmap,谁知凡事应有度,过了火就会伤及自身。实际malloc得到的内存递减是在提醒我们mmap的空间已经接近危险的边缘,如果再继续增大数据段的上限,就会出现系统启动失败的问题了。
作者: 雨丝风片    时间: 2006-03-29 09:32
Linux和NetBSD把mmap的生长方向从自底向上改为自顶向下之后,heap和mmap都有机会(是各自而不是同时)占用更大的地址空间。和原来的(FreeBSD的)地址空间布局比较起来,FreeBSD的mmap挡在了heap的前面,而Linux和NetBSD的mmap却挡在了stack的前面。关于这一点,在前面所引的Linux的【Reorganizing the address space】一文中已有说明:

There are a couple of disadvantages to this approach. One is that the stack area is rather more confined than it used to be. The actual size of the stack area is determined by the process's stack size resource limit, with a sizable cushion added, so problems should be rare.

也就是说,把mmap挪到stack前面之后,虽然解放了heap,但stack的日子可就没原来那么滋润了。
作者: Alligator27    时间: 2006-03-29 09:40
我明白你的意思了.  我试的RedHat AS 3 是linux 2.4.21 kernel

不过malloc用作管理的内存是不应该叫页面的. 而且我所知的malloc都不用mmap来获得这部分内存, 起码这样大大减少了用户的default heap空间, 如果mmap不是从顶往下.

Linux RedHat 不是这样的.

前面数据是非常规则的线性关系. 但我觉得不是因为malloc不能mmap到它想要的内存.
作者: 雨丝风片    时间: 2006-03-29 10:08
原帖由 Alligator27 于 2006-3-29 09:40 发表
我明白你的意思了.  我试的RedHat AS 3 是linux 2.4.21 kernel

不过malloc用作管理的内存是不应该叫页面的. 而且我所知的malloc都不用mmap来获得这部分内存, 起码这样大大减少了用户的default heap空间, 如果mmap不是从顶往下.

Linux RedHat 不是这样的.

前面数据是非常规则的线性关系. 但我觉得不是因为malloc不能mmap到它想要的内存.  ...



呵呵,反正就是个名字,叫什么还不都一样,。在没有特别注明的情况下,我所指的都是FreeBSD/NetBSD目前使用的malloc,作者为Poul-Henning Kamp。在这个malloc里,它的“page”定义为4K大小,它就是以这4K为单位来通过sbrk和内核进行内存交易的。而这个malloc的“page directory”空间就是用mmap来分配的,一个page在里面只占一条记录,因此这个空间不会很大,而且在FreeBSD里,heap的上限是写死了的,mmap就以此上限为底,向上生长,单从地址空间角度来看,用不用mmap是不会影响到heap的潜在生长能力的。所以,用mmap来分配“page directory”的空间是不会出现“大大减少用户的default heap空间”的问题的。

关于这个线性关系,可以用网络打个比方。许多的主机通过边缘路由器汇接到核心路由器上,于是,核心路由器上的一个网口可能就对应着众多的主机,我们假设每个网口对应的主机数目是相同的。我们把那些主机想象成实际需要malloc的内存,也就是“page”,而把核心路由器想象成“page directory”,这是需要用mmap来分配的。所以,如果由于某种原因导致核心路由器上的一个网口坏了,那影响的将是一大片的主机的通信。而坏掉的网口数目和受到影响的主机的数目之间也存在着一个完全相同的线性关系。所以,虽然“page directory”本身占据的空间不大,但是一旦它分配失败,那将导致巨大数量的内存malloc失败。

Linux使用的应该是“gnumalloc”吧?关于Linux的地址空间布局以及malloc和mmap的实现方法,我也只是从文档上看到了只言片语,尚未深入代码分析。
作者: Alligator27    时间: 2006-03-29 10:37
不错, 不是malloc大大减少用户的default heap空间, 而是vmm对mmap的布局造成的.

我能想到的唯一原因, VMM把mmap从下向上排, 可能是backword compatibility. 有些老程序, 也许依赖于stack是很深的.
作者: zzbwang    时间: 2006-03-29 12:01
大家讨论了半天,还是没有告诉BSD进程到底可以使用多大的内存空间啊。如果我在服务器上装了4GB内存,MAXDSIZ最大可以设置成多少不会出问题?可以设置成3800MB吗?
作者: colddawn    时间: 2006-03-29 12:19
那下一步的实验是不是就该想办法在各个系统上扩大Stack来观察盏增长情况以及最大值了?
作者: congli    时间: 2006-03-29 12:27
原帖由 zzbwang 于 2006-3-29 12:01 发表
大家讨论了半天,还是没有告诉BSD进程到底可以使用多大的内存空间啊。如果我在服务器上装了4GB内存,MAXDSIZ最大可以设置成多少不会出问题?可以设置成3800MB吗?

倒,兄弟认真看就知道
作者: Alligator27    时间: 2006-03-29 12:36
原帖由 雨丝风片 于 2006-3-29 10:08 发表



呵呵,反正就是个名字,叫什么还不都一样,。在没有特别注明的情况下,我所指的都是FreeBSD/NetBSD目前使用的malloc,作者为Poul-Henning Kamp。在这个malloc里,它的“page”定义为4K大小,它就是 ...


刚看了PHK malloc 和他写的 "Malloc Revisited". 你说的没错, PHK malloc 确实是mmap一块内存作page-directory. 他根据brk的值确定需要的page-directory的大小. 所以32bit进程大约要3GB/4KB*4Bytes=3MB. 考虑到不是一次分配, 6MB 的空间就够了. 一些shared libs在占一些mmap空间. 还是有一点对不上数.

PHK malloc 做得不错, 但有几点不好, 让我有点意外.
1 page-directory的大小是根据brk的值确定, 象LZ的测试程序是1MB的内存块, 与同样总内存但是1KB的内存块要分配同样大小的page-directory, 有点浪费.
2 brk() 失败后, 没有用mmap. 这样有不少空间没法给用户.
3 page-directory应当一次性分配, 而不要expand.

蛮有意思.

对了, Linux的malloc就是Kamp说的gnumalloc. 更常叫的是PTmalloc2(Wolfram Gloger), 或Doug Lea malloc.

[ 本帖最后由 Alligator27 于 2006-3-31 10:25 编辑 ]
作者: 雨丝风片    时间: 2006-03-30 15:24
原帖由 Alligator27 于 2006-3-29 12:36 发表
PHK malloc 做得不错, 但有几点不好, 让我有点意外.
1 page-directory的大小是根据brk的值确定, 象LZ的测试程序是1MB的内存块, 与同样总内存但是1KB的内存块要分配同样大小的page-directory, 有点浪费.

page directory的大小确实是根据brk的内存大小来确定的,不知道你所说的浪费是指什么?page directry是用来管理malloc内部4K大小的page的,因此每个page都会对应一个条目。但page仅仅是malloc和内核的交易单位,在malloc内部,对于page的使用则有批发和零售两种。所谓批发就是按page的整数倍提供给malloc的用户使用,对于这些page,malloc只会为其分配一个page directory中的条目,再无其它。所谓零售,则是指那些大小为16、32、64、128、256、512、1024、2048的内存块,为了向用户提供这些类型的内存块,malloc就需要把自己管理的page打碎使用,一个page只能按一种规格打碎。对于每一个被打碎了的页面,malloc需要另外为其(在heap上)分配一个pginfo结构体,用于记录这个page的碎片规格、碎片总数、空闲碎片总数,以及用于快速定位空闲碎片的比特掩码等信息。实际上,page directory里面存放的就是指向pginfo结构体的指针,再由pginfo结构体指向实际的page。只是对于那些未被打碎的page来说,由于没有pginfo结构体,因此directory里面的对应条目就用来存放一些标识该page属性的标志了。

原帖由 Alligator27 于 2006-3-29 12:36 发表
2 brk() 失败后, 没有用mmap. 这样有不少空间没法给用户.

关于这一点,我觉得谈不上好不好,只是系统设计遵循的原则不同而已。有的系统的想法是不管是米饭还是馒头,能吃饱就行,哪儿那么骄气!而有的系统则尊重用户的知情权,米饭不够就多做点米饭,馒头不够就多做点馒头。一个人的主食种类和饭量一般都是固定的,很少会突然哪一天就想多吃一斤米饭的,因此买卖双方很容易就达成默契了。

原帖由 Alligator27 于 2006-3-29 12:36 发表
3 page-directory应当一次性分配, 而不要expand.

page directory确实可以一次性分配,现有方案以两个page为单位来扩展directory,其实也包含了一种“预分配”的概念在里面,只是没有一次性分配“预”得那么夸张而已。这个问题各有利弊,不好一概而论。不知道库函数里面有没有这种一次性抢占地盘的先例?
作者: 雨丝风片    时间: 2006-03-30 15:25
我和congli将malloc的源代码剥离出来,通过修改,加入调试信息,构建了一个克隆版本的malloc。在此基础上进行了两次实验,得到了一些结果。

1、可以确定,把数据段上限调整到2934M左右的地方出现的malloc所得内存反而下降的原因就是因为通过mmap扩展page目录失败。出错代码位置为:
  1. _____________________________________________________________________FreeBSD6.0
  2. 384      /* Get new pages */
  3. 385      new = (struct pginfo**) MMAP(i * malloc_pagesize);
  4. 386      if (new == MAP_FAILED)
  5. 387          return (0);
  6. ______________________________________________/usr/src/lib/libc/stdlib/malloc.c
复制代码


2、两次实验的数据段分别设置为2934M和2935M,而两次的起始mmap位置分别为0xbf767000和0xbf867000,相差1M,证实了数据段对mmap生存空间的压缩。0xbf767000距内核空间只有8M,0xbf867000距内核空间就只有7M了,随着数据段的进一步增长,这个空间还会进一步压缩。注意,在这只有几M的空间中还有另外一个重要角色,stack。因此,mmap实际可用的空间还会更少。

3、malloc对page目录的扩展是以2个page,也即8192字节为单位进行的。扩展过程为先分配好新的page目录的空间,然后把旧的page目录的内容拷贝过去,最后再把旧的page目录释放掉。还有一点,mmap寻找空闲空间的算法是从低地址开始的first fit,这可以参考我写的关于FreeBSD虚存系统splay树的代码分析的文章。因此,只要“前面”空出了足以容纳新的page目录的空间,mmap就会杀个回马枪。因此,malloc扩展page目录时的mmap的内存使用模式大致如下图所示:


我们把mmap的每一轮同方向的增长称为一“级”。我们可以看到,除第一级稍有特殊情况之外,其余的级都是包含三次扩展,然后就会在“前方”出现可以容纳新的page目录的空间,于是mmap又从起始地址开始分配,开始新的一“级”。图中,每一条黑线的长度表示的就是malloc的page目录当前占有的内存空间。

同样,除了刚开始有一些例外之外,mmap对内存的最大要求,也即mmap“最远”到达的内存位置是由每一级的最后一次扩展的结束地址来定义的。如果内存有限,那么扩展失败就肯定出现在每一级的最后一次扩展上。如果把图画得更深一些,这个规律就会更明显。于是,我们想象有一跟纵向的“线”在图中左右移动,这根线就是mmap的生存空间的边界,它对page目录的扩展有没有什么规律?

我们以4096为一个单位来进行简单的推导,当然,还是需要忽略掉开头的情况。设第n级的第一根线的长度为B(n),所有的B(n)构成一个等差数列,通项为B(n)=6n-3, (n>=2)。设第n级的最“远”内存需求,也即这一级最后一次扩展的结束地址为L(n),显然这也是一个等差数列,通项为L(n)=18n-3, (n>=2)

1M的空间相当于256个单位,我们关心的是上图中如果在横向缩短256个单位,会对图中的最长黑线长度产生什么影响?由于mmap的“右边”是stack,何时终止并不确定,因此我们就向左边对齐,用两次相差256个单位的边界来估计这种影响的大致数量。

首先假定右边界就是256个单位(此时的mmap空间为1M),即Ln=18n-3=256,得出n=14,即共可允许18级、54次扩展。此时的page目录空间为85个单位,348160字节,87040个条目。对应于heap上的87040个page,共340M。也就是说,如果mmap的生存空间为1M,malloc就可以在heap上分配340M的空间。

现在,我们把右边界向右移动256个单位(此时的mmap空间为2M),即Ln=18n-3=512,得出n=28,即此时共可允许28级、84次扩展。此时的page目录空间为169个单位,692224字节,173056个条目。对应于heap上的173056个page,共676M。

同样,当把右边界再次右移256个单位之后,页面目录对应的heap上的空间为1012M。。。

676 - 340 = 336,1012 - 676 = 336,也就是说,mmap空间每变动1M对heap空间的影响就是336M。这个336M正是前面的实验中发现的非常规则的线性关系中的递减步长。理论推导和实验结果完全一致。


关于上面推导过程的几点补充说明:

1、malloc对page目录的扩展是“搬家”式的。也就是说,当决定需要对page目录进行扩展的时候,就以新的尺寸、通过mmap系统调用、按first fit原则找到一块满足要求的区域,将旧的区域中的内容全部拷贝过去,然后再将旧的区域释放。

2、至于前面所给图中为何会出现规律性的“回头”现象,我们仍然按4096一个单位来描述。假设在某一级的开始,也就是从最左边的mmap的起始地址开始,这次的page目录记为A。之后进行扩展,按first fit原则找到的第一个满足要求的空闲空间就紧挨在A的后面,也就是B。我们把页面目录拷贝到B,同时将A的空间释放,显然,B要比A大两个单位。之后再次进行扩展,虽然前面有一个空闲空间A,但它并不“fit”,第一个fit的空闲空间位于B的后面,也即C,我们就把页面目录拷贝到C,同时将B释放,同样,C要比B大两个单位。另外,相邻的两个空闲空间A和B会被合并,记为AB。之后再次进行扩展,我们需要找到一个比C大两个单位的空间D,AB是遇到的第一个空间,但它是否“fit”呢?这可以转换成一个不等式问题。D等于a+6,AB等于2a+2,于是AB > D 也就成了2a+2 > a+6,解这个不等式,得a>4。

也就是说,只要最左边的那次(A)扩展后的page目录超过4个单位,那么在经历了B、C之后,AB合起来的空闲空间就肯定能够存放D。于是整幅图就呈现出了一种极有规律的“三步一回头”的景象。我们也正是基于这个事实才在上面的推导过程中提出了“级”的概念。

3、关于336的计算过程,需要对malloc的源代码有一定的了解。不过理解上面的推导不需太多的细节。此处是一个稍微详细一点的版本,以mmap空间为256个单位为例。首先通过公式Ln=18n-3=256算出n等于18,也就是说,256个单位的mmap空间总共可以允许18级扩展成功结束,其中每一级包括3次扩展,也就是总共54次扩展。显然,经过第54次扩展之后的page目录最大,有多大呢?注意,这个第54次扩展之后的page目录是第18级上的第三次扩展,而我们前面已经给出了每一级的第一次扩展的大小公式,即B(n)=6n-3。于是,我们可以求得第52次扩展之后的page目录的大小为B(18 )=81,而第54次比第52次大4个单位,于是第54次扩展之后的page目录的大小就是85个单位。一个4096的heap页面对应于page目录中的一个条目,一个条目是4个字节。所以,如果page目录此时占有85个单位,一个单位是4096字节,因此page目录就有85*4096=348160字节,那它就有348160/4=87040个条目,对应于87040个heap上的4K页面,共计356515840字节,即340M。

4、关于两个公式的推导,其中,B(2)=9得自实验数据。

      B(n) = B(n-1) + 6                    (n>=3)
      B(2) = 9
推出  B(n) = 9 + (n - 2) * 6
           = 6n - 3                        (n>=2)

      L(n) = B(n) + B(n) + 2 + B(n) + 4
           = 18n - 3                       (n>=2)


[ 本帖最后由 雨丝风片 于 2007-4-21 10:25 编辑 ]
作者: congli    时间: 2006-03-30 15:49
惭愧
全是兄弟的努力,呵~~
作者: 雨丝风片    时间: 2006-03-30 16:20
原帖由 congli 于 2006-3-30 15:49 发表
惭愧
全是兄弟的努力,呵~~


实验数据才是最宝贵的财富!

附上我们修改后的malloc.c和取得的2934、2935两组数据:

malloc.c

29.86 KB, 下载次数: 72

mm2934.txt

103.65 KB, 下载次数: 76

mm2935.txt

80.81 KB, 下载次数: 69


作者: Alligator27    时间: 2006-03-30 22:08
原帖由 雨丝风片 于 2006-3-30 15:24 发表

page directory的大小确实是根据brk的内存大小来确定的,不知道你所说的浪费是指什么?page directry是用来管理malloc内部4K大小的page的,因此每个page都会对应一个条目。但page仅仅是malloc和内核的交易单位, ...

Excellent work!  

让我解释一下我的意思.

1 如果把page directory看成一个array, 它的index是page number, 它的element是该page的管理信息(meta data). 如果用户程序的内存申请size远大于pagesize, 象LZ的测试程序是1MB的内存块, 那么page directory是sparse array. 所以我说有点浪费.

2 malloc不考虑mmap是不行的. 特别象FreeBSD, default heap的顶被mmap area固定了. 当brk到这个顶的时候, 用户不能再得到内存, 但mmap area还有很多空间. 这不是米饭/馒头的选择, 会饿死的. 换句话说, 不管kernel把mmap起始地址放哪儿, malloc都应当分配出~3GB给用户程序.

3 page-directory一次性分配只需要3MB (32bit), 而且只是virtual address. 完全值得. 第一, 只有一个sysem call. 第二, 不会有将来分配不到的可能. 第三, 因为不搬家,实际占用空间可能少一些.
作者: 雨丝风片    时间: 2006-03-31 08:54
原帖由 Alligator27 于 2006-3-30 22:08 发表
1 如果把page directory看成一个array, 它的index是page number, 它的element是该page的管理信息(meta data). 如果用户程序的内存申请size远大于pagesize, 象LZ的测试程序是1MB的内存块, 那么page directory是sparse array. 所以我说有点浪费.

1、page目录中的条目和malloc管理的page之间有一一对应的关系,这和用户申请内存的大小是无关的。每个页面都要在这儿登个记,因此应该没有“稀疏”的问题。你的意思是不是说如果用户申请的内存是1M,相当于256个page,于是就需要256个page目录条目,而你认为其实只要找一个地方记录就可以了?我觉得这里还是要明确一下page目录的作用,它并不是用来记录所有分配给用户的内存的头指针的,它仅仅是用来记录malloc自身管理的每一个page的。你这次虽然是把256个页面作为一个整体交给了用户,但在用户将其释放之后,它们仍然处于malloc的管理之下,身份就变成了256个独立的空闲page。malloc就可以用它们来满足用户未来的各种分配需求,而且只要它们能满足,malloc就没有必要再去调用brk向系统要内存。基于上述意义,每一个page目录的条目都是“有用的”,因此不会有“稀疏”的问题。

原帖由 Alligator27 于 2006-3-30 22:08 发表
2 malloc不考虑mmap是不行的. 特别象FreeBSD, default heap的顶被mmap area固定了. 当brk到这个顶的时候, 用户不能再得到内存, 但mmap area还有很多空间. 这不是米饭/馒头的选择, 会饿死的. 换句话说, 不管kernel把mmap起始地址放哪儿, malloc都应当分配出~3GB给用户程序.

2、我觉得米饭馒头的比喻能够很好的说明这个问题。有的系统只管让顾客闭着眼睛吃饱,至于给你吃的是什么你别管。而有的系统则希望让顾客自己来选择,如果把米饭吃完了还没吃饱的话,要么你就把米饭多做一点,要么你就再吃两个馒头。回到内存话题,有的系统认为用户想要的就是内存,而对这块内存是从哪儿来的并不关心,于是在有些情况下就会用mmap来冒充malloc。而有的系统则认为用户有权自己去安排自己的地址空间,他有权决定自己申请的内存是来自heap的还是来自mmap的。如果heap的空间不够,你可以调整heap的大小,你也可以安排你的程序使用mmap。有时候,只管吩咐、什么事都让别人做了确实很方便,但DIY的感觉也确实不错啊!

原帖由 Alligator27 于 2006-3-30 22:08 发表
3 page-directory一次性分配只需要3MB (32bit), 而且只是virtual address. 完全值得. 第一, 只有一个sysem call. 第二, 不会有将来分配不到的可能. 第三, 因为不搬家,实际占用空间可能少一些.

3、这一点确实值得考虑和尝试。page目录现在的空间浪费确实就是因为搬家引起的,否则我也没必要去推算mmap空间的1M会影响heap上的多少M了。我唯一的担心就是,库函数“兴不兴”这样抢地盘?
作者: Alligator27    时间: 2006-03-31 10:27
原帖由 雨丝风片 于 2006-3-31 08:54 发表

1、page目录中的条目和malloc管理的page之间有一一对应的关系,这和用户申请内存的大小是无关的。每个页面都要在这儿登个记,因此应该没有“稀疏”的问题。你的意思是不是说如果用户申请的内存是1M,相当于256个 ...

我们是从不同的角度看这个问题.

1 同意. PHK的用意是page mapping. 我想说的是, 它是作的最坏打算, 既用户的粒度是page. 如果用户使用大内存块, 它就有浪费, 虽然不多, 因为一个用户块实际上只需要一条目录. 不过使用mapping的malloc都是这样, 无可厚非. 只是在你的测试中显示出这个问题.

2 用户是不用关心内存是从main heap, 还是从mmap里来的, 这点我完全同意. 但用户一定想用尽量多的内存, 不管从哪儿来, 怎么来, 我只要不断malloc, 它就应当给我3GB. 这是PHK最大的缺点. 我想这也是该帖的主题.

3. 库函数可不可以抢地盘. 看你问谁了. 有些用户可能会panic. 因为"hello world"的memory footprint 就有3MB. 但不会有什么实际影响的.
作者: 雨丝风片    时间: 2006-03-31 11:50
原帖由 Alligator27 于 2006-3-31 10:27 发表

我们是从不同的角度看这个问题.


1、单元化只是为了内存管理的方便。如果用户申请32字节,我就用一个指针记录这个32字节的块,如果用户申请1M,我就用一个指针记录这1M的块,暂时倒是省了空间,但这1M的空间被用户释放之后怎么办?直接还给系统还是继续由malloc管理?反个方向,如果用户申请的内存小于现有的page大小,比如32、64、128,那按你的想法,每个块都存一个指针,岂不是也要浪费空间了? 将内存单元化管理虽然会为每个单元记录一个信息,但由此带来的管理效率却是巨大的。

2、3、用户想用尽量多的内存的方法有很多,不一定非得在malloc上一条路走到黑,当然,如果这后面的工作由系统来做了,对于用户来说还是极为方便的。此外,在未来的FreeBSD7.0里面,现有的malloc将被Jason Evans完全替换。
作者: 雨丝风片    时间: 2006-04-11 19:52
看了新出的【Understanding the Linux Kernel】第三版,书中第二十章专门讲到了Linux的新的内存布局(819页):

Linux是在2.6.9版本中引入所谓的“flexible memory region layout”的,从本质上说,就是一个进程的内存布局取决于它的用户模式栈预期能长多大。不过仍然可以使用传统的布局方式,主要用于内核无法限制用户模式栈的大小的时候。

  1.                            传统布局                                灵活布局
  2. 代码段:                                  始于0x08048000

  3. 数据和bss段:                             紧跟代码段之后

  4. 堆:                                    紧跟数据和bss段之后

  5. 文件内存映射      始于0x40000000(这个地址               始于接近用户模式栈末尾(最低地址)
  6. 和匿名内存区域:  相当于整个用户模式地址空               的地方,库被添加在后续的低地址中。
  7.                   间的1/3),库被添加在后续
  8.                   的高地址中。

  9. 用户模式栈:                         始于0xc0000000,向低地址生长
复制代码




一般来说,如果内核能够通过RLIMIT_STACK得到一个用户模式栈的尺寸上限,那它就使用灵活布局。这个限制定义了保留给栈的线性地址空间,但是,这个大小不能小于128 MB,也不能大于2.5 GB。

如果RLIMIT_STACK被设为“无穷大”,或者系统管理员把sysctl_legacy_va_layout变量设为1,内核就无法确定用户模式栈的上限,于是就选择传统的内存区域布局。
作者: 雨丝风片    时间: 2006-05-19 09:27
在bsdcan2006上面看到Jason Evans写的关于FreeBSD新的jemalloc的论文了。
作者: gvim    时间: 2006-05-19 10:10
谢谢!!!!!!!
这几天昏的把这件大事忘了,12号就开始开会了,过了一个星期要不是你提醒都忘了
作者: assiss    时间: 2007-04-21 10:47
2006年3~5月我在外做实验,竟然错过了这么精彩的讨论。
作者: 雨丝风片    时间: 2007-04-21 11:05
原帖由 assiss 于 2007-4-21 10:47 发表
2006年3~5月我在外做实验,竟然错过了这么精彩的讨论。


呵呵,那次真的是一次千里之外研发合作的愉快经历,初步测试、大胆猜测、理论分析、设计试验、准备测试代码,实测大量数据、试验数据分析、归纳数学模型、完成理论推导。。。一切就在网络穿梭中水到渠成了,痛快淋漓啊,呵呵!
作者: 大大狗    时间: 2007-04-21 11:43
原帖由 assiss 于 2007-4-21 10:47 发表
2006年3~5月我在外做实验,竟然错过了这么精彩的讨论。

当时我还不知道有BSD这个系统呢 ~_~
作者: congli    时间: 2007-04-21 14:09
原帖由 雨丝风片 于 2007-4-21 11:05 发表


呵呵,那次真的是一次千里之外研发合作的愉快经历,初步测试、大胆猜测、理论分析、设计试验、准备测试代码,实测大量数据、试验数据分析、归纳数学模型、完成理论推导。。。一切就在网络穿梭中水到渠成了,痛 ...

合作愉快:em11:
作者: gvim    时间: 2007-04-21 17:07
可以多找一些论题大家一起来讨论.
作者: assiss    时间: 2007-04-21 17:52
这是一次很经典的讨论。
我想可以复制其成功经验。

支持GVIM的意见,是不是你们一起出面组织一些讨论?
作者: gvim    时间: 2007-04-21 18:04
原帖由 assiss 于 2007-4-21 17:52 发表
这是一次很经典的讨论。
我想可以复制其成功经验。

支持GVIM的意见,是不是你们一起出面组织一些讨论?


我现在的公司上网不是很方便,家里也还没有开网线, 所以组织论题的事情需要其他几位版主和相关高手筹划.
我觉得要推广BSD一个很关键的问题是驱动, 所以我从春节到现在的闲暇时间一直都在整{Free, Net}BSD的驱动(我的blog里有一些没来得急整理和完成的东西), 目前正在分析USB这一块,希望可以尽快完成框架.

如果大家有兴趣讨论{Free, Net}BSD驱动方面的问题,我想大家可以一起讨论. 呵呵.

[ 本帖最后由 gvim 于 2007-4-21 18:31 编辑 ]
作者: 雨丝风片    时间: 2007-04-21 22:31
原帖由 assiss 于 2007-4-21 17:52 发表
这是一次很经典的讨论。
我想可以复制其成功经验。

支持GVIM的意见,是不是你们一起出面组织一些讨论?


好建议。只要有好的话题,不需要组织就可以讨论得很精彩。不必为了讨论而讨论,最好就像这次一样,以解决某个实际问题为目标,顺藤摸瓜,越摸越深。。。
作者: 雨丝风片    时间: 2007-04-21 22:33
原帖由 gvim 于 2007-4-21 18:04 发表
我现在的公司上网不是很方便,家里也还没有开网线, 所以组织论题的事情需要其他几位版主和相关高手筹划.
我觉得要推广BSD一个很关键的问题是驱动, 所以我从春节到现在的闲暇时间一直都在整{Free, Net}BSD的驱 ...


51之后我们两个面谈一下。。。:em11:
作者: congli    时间: 2007-04-21 23:16
原帖由 雨丝风片 于 2007-4-21 22:33 发表


51之后我们两个面谈一下。。。:em11:

不是应该说会师一下吗
作者: panabit    时间: 2008-10-09 14:13
原帖由 雨丝风片 于 2006-3-28 17:14 发表



辛苦辛苦!

从试验结果来看,的确是随着数据段的逐渐增长,mmap的生存空间被不断压缩,使得基于mmap的各种库陆续出现分配不到空间的情况,最终导致系统启动失败。

另外,在2934M之前,实际ma ...


无所谓mmap空间被压缩这样的概念。
mmap是所有内存分配的根源,无论你是使用malloc,还是其它方法,最终都是通过mmap来实现的。
所谓的数据段,代码段和堆栈,那只是程序语言系统的概念,OS并不理会这些。
这些段的映射都是通过mmap来实现的。

还是那句话,mmap是OS所提供的,open给应用程序的唯一一个API接口。
在Unix里,mmap是一个非常重要的API,它关联了内存和文件这连个重要的资源。
作者: crastyl    时间: 2008-10-17 00:34
还有高手
作者: 雨丝风片    时间: 2008-10-17 16:10
原帖由 panabit 于 2008-10-9 14:13 发表
无所谓mmap空间被压缩这样的概念。
mmap是所有内存分配的根源,无论你是使用malloc,还是其它方法,最终都是通过mmap来实现的。


当时讨论中使用的“mmap空间”只是对“文件内存映射和匿名内存区域”的一个形象描述,并非技术术语,
这个结合讨论上下文即可理解。

原帖由 panabit 于 2008-10-9 14:13 发表
所谓的数据段,代码段和堆栈,那只是程序语言系统的概念,OS并不理会这些。
这些段的映射都是通过mmap来实现的。


请参考:http://blog.chinaunix.net/u/9831/showart_110254.html

原帖由 panabit 于 2008-10-9 14:13 发表
无所谓mmap空间被压缩这样的概念。
mmap是所有内存分配的根源,无论你是使用malloc,还是其它方法,最终都是通过mmap来实现的。
所谓的数据段,代码段和堆栈,那只是程序语言系统的概念,OS并不理会这些。
这些段的映射都是通过mmap来实现的。

还是那句话,mmap是OS所提供的,open给应用程序的唯一一个API接口。
在Unix里,mmap是一个非常重要的API,它关联了内存和文件这连个重要的资源。


我无法从你的整段描述的上下文中判断出所出现的每一处“mmap”是指系统调用还是其它的什么东西。
如果你全部都指得是mmap系统调用,那么你的整段描述就是混乱的。而且,可以明确的说,在我们所
讨论的malloc库函数版本里,他所使用的动态内存是通过两个系统调用获取的,一个是brk,一个是mmap。
不过我想,在你整段描述中出现的“mmap”的含义似乎并没有这么明确。

综合你的:“mmap是OS所提供的,open给应用程序的唯一一个API接口。”
“这些段的映射都是通过mmap来实现的。”
是否可以推论出:“应用程序”是通过“mmap”这个唯一的“API”来映射自己的数据段、代码段和堆栈的?
作者: panabit    时间: 2008-10-17 18:00
原帖由 雨丝风片 于 2008-10-17 16:10 发表


当时讨论中使用的“mmap空间”只是对“文件内存映射和匿名内存区域”的一个形象描述,并非技术术语,
这个结合讨论上下文即可理解。



请参考:http://blog.chinaunix.net/u/9831/showart_110254.htm ...


有几个层面的东西需要分开:

1. OS层面

   在OS眼里,如果从内存管理角度看,它基本上不意识到某个程序的数据段或堆栈段的区别性。这对它而言都是虚拟内存
   空间所占用的不同地址范围。mmap是OS用来给进程提供的分配和管理这个3G虚拟空间的API。

2. loader

   loader在加载应用程序时,根据elf文件中的信息,使用mmap将应用程序的代码section,各个数据section(如bss)
   使用mmap保留elf文件中需要指定的虚拟空间的区域。注意,由于现代OS对物理内存的allocate on demand特性,此
   时保留虚拟空间的区域并不意味OS为你分配了相对应的物理内存。这个物理内存的分配只有在你从elf文件中拷贝数据到
   相应的虚拟内存区域中才会发生(此时硬件会产生缺页exception,exception handler会分配物理内存并建立虚拟到
   物理的映射)。另外你也可以使用mlockall()等让这种物理内存分配动作强制发生。

3. libc runtime中的malloc

    首先我想大家都明白,malloc是一个library function,而不是一个syscall API。malloc要做的事情就是处理进程被load
    后剩余的虚拟空间(当然不包括elf的entry之前的那部分小空间),malloc的处理是从低到高处理,从栈反方向增长。它也
  使用mmap来保留自己需要的虚拟空间。但是malloc所分配的内存是受runtime library参数限制的。所以这就导致了堆和
   栈之间出现了一个巨大的"hole"。对于这个hole,只能使用mmap来分配。 当然,你可以更改library的参数来缩小这个
  hole。

 引入malloc()有几个原因:
  1) 让用户分配更小尺寸的内存块(mmap必须以PAGE为单位)
  2) 提供一个比mmap更有效的内存使用和分配策略,比如buddy策略(或算法)。

正是如上所述,所以我认为,所有内存分配的根源都是mmap()。至于您所说的brk或sbrk,现在基本上已经被抛弃了,它们的
存在是由于"legency",因为它所做的事情不需要从OS层面去实现,在runtime library里即可。

不当之处,欢迎大家指正!
作者: panabit    时间: 2008-10-17 18:01
原帖由 雨丝风片 于 2008-10-17 16:10 发表


当时讨论中使用的“mmap空间”只是对“文件内存映射和匿名内存区域”的一个形象描述,并非技术术语,
这个结合讨论上下文即可理解。



请参考:http://blog.chinaunix.net/u/9831/showart_110254.htm ...


"是否可以推论出:“应用程序”是通过“mmap”这个唯一的“API”来映射自己的数据段、代码段和堆栈的?"

------>对,应该是这样的。
作者: 雨丝风片    时间: 2008-10-20 16:26
原帖由 panabit 于 2008-10-17 18:00 发表


有几个层面的东西需要分开:

1. OS层面

   在OS眼里,如果从内存管理角度看,它基本上不意识到某个程序的数据段或堆栈段的区别性。这对它而言都是虚拟内存
   空间所占用的不同地址范围。mmap是OS用 ...


实事求是的说,你上面这些话的绝大部分都是正确的,不过我困惑的是,你对我们的讨论的异议体现在哪里,或者说,
你把这么一大段论述放在这个讨论里的含义是什么。所以,我建议你从头到尾再仔细的阅读一下这个讨论的全过程中
每一个人的发言,弄明白这个讨论想要解决和解决了什么问题,以及这个讨论所基于的malloc的具体版本的实现方案,
至于其它的东西,至少在这个讨论里,我个人没有兴趣涉及。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2