Chinaunix

标题: 『请教』get_free_pages申请大内存 [打印本页]

作者: crazymouse99    时间: 2009-10-14 16:05
标题: 『请教』get_free_pages申请大内存
想申请几百兆甚至1个GB的内核空间,请问该怎么处理。

百度搜索过,说get_free_pages 能分配的最大空间为4K×1024,约4M,远远不够我的要求呀。


是不是要重新编译内核?是的话应该是个什么样的处理过程,请大侠赐教,多谢多谢~~
作者: kouu    时间: 2009-10-14 16:13
申请这么大的空间有何用意呢? 32位系统下,内核的地址空间只有1G,并且其中还有128M是没有建立固定映射的……

估计重新编译内核是搞不定的, 修改内核代码也是不现实的, 考虑换内核吧~
作者: chenda0.03    时间: 2009-10-14 16:46
get_free_pages是用来申请物理连续的页,当然不可能很大

“vmalloc  -  allocate virtually contiguous memory”
vmalloc会从高端内存分配,并且线性连续,它使用内核空间高128M线性地址。
还是不可能达到你的需求,1GB有点过分了。。。

内核空间就1GB大,兄台要做什么
作者: crazymouse99    时间: 2009-10-14 16:50
没有映射可以自己做内存映射的吧....

那换个角度讲,不要1GB那么大,我想申请200M的空间该怎么处理呢?


作者: chenda0.03    时间: 2009-10-14 16:57
原帖由 crazymouse99 于 2009-10-14 16:50 发表
没有映射可以自己做内存映射的吧....

那换个角度讲,不要1GB那么大,我想申请200M的空间该怎么处理呢?



既然在内核空间了,自己做映射是可以的,但是你如果动了内核的页表,那就很危险了,完全需要自己来维护这部分内存了,你能保证安全吗?
如果你的物理内存不够大,那是很难拿到200M的连续内存的,如果很大,我想在高端内存应该还是有可能的。
作者: chenda0.03    时间: 2009-10-14 17:00
对了,你要申请200M的内核空间,如果低端内存没有连续的200M,也就意味着内核没有200M连续的线性地址给你使用,我看是没办法了
作者: kouu    时间: 2009-10-14 17:09
很好奇LZ的需求是什么……
LZ想要的东西基本上是不可能了,就算改代码也够呛。

LZ如果把你的需求说出来,或许还有可以变通的方法
作者: hb12112    时间: 2009-10-14 19:03
两种方法:
1 采用预留的方式,在内核态用io_remap.
2 alloc_bootmem分配,要修改内核.在内核启动的时候分配.
作者: chenda0.03    时间: 2009-10-14 20:20
原帖由 hb12112 于 2009-10-14 19:03 发表
两种方法:
1 采用预留的方式,在内核态用io_remap.
2 alloc_bootmem分配,要修改内核.在内核启动的时候分配.


请教:alloc_bootmem的使用和实现。
第一次见到这个函数,请大侠赐教啊
作者: walle0_0    时间: 2009-10-15 14:09
32位环境下是不可能超过896M,否则还要申请高端内存映射到内核
64位环境下面可以自己管理一个内存链表,链表中每个单元用__get_free_pages申请
作者: Godbach    时间: 2009-10-15 14:18
内核版不时的就有帖子问如何申请大内存。。。。

建议仔细考虑一下你的需求吧
作者: crazymouse99    时间: 2009-10-15 16:07
原帖由 Godbach 于 2009-10-15 14:18 发表
内核版不时的就有帖子问如何申请大内存。。。。

建议仔细考虑一下你的需求吧


需求就这样:我要分配大块的内存用于保存网卡数据,再通过内存映射,供用户态使用。

我修改了max_order = 16,提高了最大可申请的大小:4K×1024×(2^5)= 128M,get_free_page也成功通过编译。

可以说这个问题暂时解决了。

但是现在又碰到另一个问题,为什么我kmolloc分配的地址会大于最大内存地址?

给我分配的地址是:ffff810230b4a480, 通过__pa()转换后为:9407079552

大于我的8G内存啊...

请问怎么回事?可能是什么原因?几位大侠的经验丰富,希望能够提点下,谢谢
作者: epegasus    时间: 2009-10-15 17:35
什么硬件配置?好象很强的机子....
作者: zyr-linux    时间: 2009-10-15 19:01
启动项加一句:mem=A;A=实际物理内存-200MB。
作者: platinum    时间: 2009-10-16 10:43
原帖由 crazymouse99 于 2009-10-14 16:50 发表
没有映射可以自己做内存映射的吧....

那换个角度讲,不要1GB那么大,我想申请200M的空间该怎么处理呢?


vmalloc 可以满足你的需求
作者: crazymouse99    时间: 2009-10-16 10:58
标题: 回复 #15 platinum 的帖子
大哥,你是来搞笑的吧

内核空间。。。
作者: platinum    时间: 2009-10-16 10:58

  1. #include <linux/module.h>
  2. #include <linux/vmalloc.h>

  3. MODULE_AUTHOR("platinum");
  4. MODULE_DESCRIPTION("This is a module sample.");
  5. MODULE_LICENSE("GPL");

  6. __u8 *data;

  7. int
  8. init_module (void)
  9. {
  10.         data = vmalloc(1024 * 1024 * 200);

  11.         if (!data)
  12.                 return -ENOMEM;

  13.         memset(data, 0xff, 1024 * 1024 * 200);
  14.         printk("module loaded.\n");
  15.         return 0;
  16. }


  17. void
  18. cleanup_module(void)
  19. {
  20.         vfree(data);
  21.         printk("module unloaded.\n");
  22. }
复制代码
root@LinuxDev /platinum/project/module
# free
             total       used       free     shared    buffers     cached
Mem:        510644     275620     235024          0      48544     168876
-/+ buffers/cache:      58200     452444
Swap:       522104          0     522104
root@LinuxDev /platinum/project/module
# insmod module.ko
root@LinuxDev /platinum/project/module
# free
             total       used       free     shared    buffers     cached
Mem:        510644     480716      29928          0      48652     168888
-/+ buffers/cache:     263176     247468
Swap:       522104          0     522104
root@LinuxDev /platinum/project/module
# rmmod module
root@LinuxDev /platinum/project/module
# free
             total       used       free     shared    buffers     cached
Mem:        510644     276232     234412          0      48732     168888
-/+ buffers/cache:      58612     452032
Swap:       522104          0     522104
root@LinuxDev /platinum/project/module
#

作者: Godbach    时间: 2009-10-16 11:18
白金兄的程序我也测试了一下,不过是虚拟机,尝试申请100M的内存:
  1. [root@localhost alloc_large_mem]# free
  2.              total       used       free     shared    buffers     cached
  3. Mem:        385624     188760     196864          0       1908      54936
  4. -/+ buffers/cache:     131916     253708
  5. Swap:       522104       8068     514036
  6. [root@localhost alloc_large_mem]# insmod alloc_large_mem.ko
  7. [root@localhost alloc_large_mem]# free
  8.              total       used       free     shared    buffers     cached
  9. Mem:        385624     290388      95236          0       1960      54948
  10. -/+ buffers/cache:     233480     152144
  11. Swap:       522104       8068     514036
  12. [root@localhost alloc_large_mem]#
复制代码


可见,insmod模块之后系统使用的内粗增加了100M多一点
作者: platinum    时间: 2009-10-16 11:23
我的也是虚拟机
作者: peimichael    时间: 2009-10-16 11:31
刚想到一个小问题,
VMALLOC_START是在high_memory之上的8M以后的,
那么假如我有1G内存,high_memory界限会划在896M吧
也就是说vmalloc最多只有128-8=120M了,这还要再除去顶端的固定内核映射等空间
那么这种情况下是不是用vmalloc无法分配到200M空间?
不知道Godbach版主只分配到100多M内存是不是这个原因。
反而当物理内存较小的时候,high_memory比较低,倒是可以分配到200M的虚拟地址空间。
也就是说vmalloc所能分配到的最大空间实际跟物理内存大小还有点关系?
物理内存越大,vmalloc能分配到的越少?
作者: Godbach    时间: 2009-10-16 11:34
原帖由 peimichael 于 2009-10-16 11:31 发表
刚想到一个小问题,
VMALLOC_START是在high_memory之上的8M以后的,
那么假如我有1G内存,high_memory界限会划在896M吧
也就是说vmalloc最多只有128-8=120M了,这还要再除去顶端的固定内核映射等空间
那么这 ...


不是的。我是系统内存剩下不到200M了,所以分了100M。下面是分了150M的情形:
[root@localhost alloc_large_mem]# free
             total       used       free     shared    buffers     cached
Mem:        385624     212368     173256          0       4972      75260
-/+ buffers/cache:     132136     253488
Swap:       522104       7992     514112
[root@localhost alloc_large_mem]# insmod alloc_large_mem.ko
[root@localhost alloc_large_mem]# free
             total       used       free     shared    buffers     cached
Mem:        385624     366024      19600          0       4988      75260
-/+ buffers/cache:     285776      99848
Swap:       522104       7992     514112
[root@localhost alloc_large_mem]#

作者: platinum    时间: 2009-10-16 11:47
原帖由 peimichael 于 2009-10-16 11:31 发表
物理内存越大,vmalloc能分配到的越少?

vmalloc 可以分配多少内存和 /proc/meminfo 有关
MemTotal:      1018680 kB
MemFree:        642760 kB
Buffers:         32800 kB
Cached:         126024 kB
SwapCached:          0 kB
Active:         243148 kB
Inactive:        94348 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      1018680 kB
LowFree:        642760 kB
SwapTotal:     2096440 kB
SwapFree:      2096440 kB
Dirty:            1224 kB
Writeback:           0 kB
AnonPages:      178728 kB
Mapped:          20260 kB
Slab:            15712 kB
SReclaimable:     4400 kB
SUnreclaim:      11312 kB
PageTables:        896 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   2605780 kB
Committed_AS:  1095916 kB
VmallocTotal:  1040376 kB
VmallocUsed:     10108 kB
VmallocChunk:  1030208 kB

启动时在 kernel 后面加参数 vmalloc=xxxM 可以指定系统允许使用多大虚拟内存空间,但这个数值必须 < 实际物理内存
至于有的机器为什么不指定也显示超大,而有的系统不指定则才 100M 左右,我就不清楚了

作者: Godbach    时间: 2009-10-16 11:52
标题: 回复 #22 platinum 的帖子
白金兄,那你分配个800M的内存看一下能否成功。
作者: Godbach    时间: 2009-10-16 11:57
刚刚试图分配300M的内存,我的系统仅剩下170多M的物理内存,分配前的情况如下:
[root@localhost alloc_large_mem]# free
             total       used       free     shared    buffers     cached
Mem:        385624     207388     178236          0       6220      76076
-/+ buffers/cache:     125092     260532
Swap:       522104       7992     514112
[root@localhost alloc_large_mem]# cat /proc/meminfo | grep Vmalloc
VmallocTotal:   638968 kB
VmallocUsed:      3512 kB
VmallocChunk:   633644 kB

加载模块,分配300M内存
[root@localhost alloc_large_mem]# insmod alloc_large_mem.ko
[root@localhost alloc_large_mem]# free
             total       used       free     shared    buffers     cached
Mem:        385624     378624       7000          0        212      20952
-/+ buffers/cache:     357460      28164
Swap:       522104      72520     449584
[root@localhost alloc_large_mem]# cat /proc/meminfo | grep Vmalloc
VmallocTotal:   638968 kB
VmallocUsed:    311032 kB
VmallocChunk:   326440 kB
[root@localhost alloc_large_mem]#

可见,物理内存减少了170M,但是从/proc/meminfo可以看出,虚拟内存由原先的3M多变成了311M,使用了300多M的虚拟内存。
作者: eexplorer    时间: 2009-10-16 12:05
标题: 回复 #22 platinum 的帖子
在386机器上,如果物理内存超过1G的话,default的vmalloc区间只有128M左右。同过vmalloc=XX参数的话,是减少了kernel线性映射空间为代价的。

在x86_64的机子上就没有这个问题,vmalloc的区间可以很大。
作者: platinum    时间: 2009-10-16 12:36

又做了一个实验

# cat /proc/meminfo
MemTotal:      1544432 kB
MemFree:       1475704 kB
Buffers:          8604 kB
Cached:          31096 kB
SwapCached:          0 kB
Active:          30860 kB
Inactive:        19308 kB
HighTotal:      786368 kB
HighFree:       741500 kB
LowTotal:       758064 kB
LowFree:        734204 kB
SwapTotal:      522104 kB
SwapFree:       522104 kB
Dirty:            2524 kB
Writeback:           0 kB
AnonPages:       10512 kB
Mapped:           3184 kB
Slab:             7696 kB
SReclaimable:     2272 kB
SUnreclaim:       5424 kB
PageTables:        192 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   1294320 kB
Committed_AS:    16540 kB
VmallocTotal:  1294328 kB    // 在启动时 kernel 里 vmalloc=1280M
VmallocUsed:      4216 kB
VmallocChunk:  1289704 kB


# free
             total       used       free     shared    buffers     cached
Mem:       1544432      68660    1475772          0       8604      31096
-/+ buffers/cache:      28960    1515472
Swap:       522104          0     522104

# insmod module.ko

# free
             total       used       free     shared    buffers     cached
Mem:       1544432    1118084     426348          0       8688      31096
-/+ buffers/cache:    1078300     466132
Swap:       522104          0     522104

# rmmod module

# free
             total       used       free     shared    buffers     cached
Mem:       1544432      69596    1474836          0       8772      31096
-/+ buffers/cache:      29728    1514704
Swap:       522104          0     522104

#

代码如下

  1. #include <linux/module.h>
  2. #include <linux/vmalloc.h>

  3. MODULE_AUTHOR("platinum");
  4. MODULE_DESCRIPTION("This is a module sample.");
  5. MODULE_LICENSE("GPL");

  6. #define MB      (1024*1024)

  7. __u8 *data;

  8. int
  9. init_module (void)
  10. {
  11.         data = vmalloc(1024 * MB);

  12.         if (!data)
  13.                 return -ENOMEM;

  14.         memset(data, 0xff, 1024 * MB);
  15.         printk("module loaded.\n");
  16.         return 0;
  17. }


  18. void
  19. cleanup_module(void)
  20. {
  21.         vfree(data);
  22.         printk("module unloaded.\n");
  23. }
复制代码

由此可见,在内核里分配并使用了 1G 内存空间,虽然实现了,但不知道用于生产环境是否可行

在386机器上,如果物理内存超过1G的话,default的vmalloc区间只有128M左右。同过vmalloc=XX参数的话,是减少了kernel线性映射空间为代价的。

在x86_64的机子上就没有这个问题,vmalloc的区间可以很大。

不知道这种代价到底有多大,对内存管理不熟悉,eexplorer 兄可否给我们讲一下

作者: peimichael    时间: 2009-10-16 12:48
白金前辈,你的vmalloc怎么有1280M阿。。你用的64系统么?
作者: platinum    时间: 2009-10-16 13:07
原帖由 peimichael 于 2009-10-16 12:48 发表
白金前辈,你的vmalloc怎么有1280M阿。。你用的64系统么?

我用的是 32bit 虚拟机,里面运行的是 32bit linux 系统 gentoo
虚拟机分配了 1536MB 内存(宿主机 2GB)
作者: epegasus    时间: 2009-10-16 13:21
标题: 回复 #25 eexplorer 的帖子
可是他却分配了1G的,...
是不是0xc0000000边界下降了?
作者: eexplorer    时间: 2009-10-16 13:56
标题: 回复 #29 epegasus 的帖子
查了一下,在compile kernel的时候有一个memory splict的选项,
可以改变PAGE_OFFSET的值。可以查一下 /lib/modules/`uname -r`/build/.config里CONFIG_PAGE_OFFSET的值。
作者: peimichael    时间: 2009-10-16 14:01
原帖由 eexplorer 于 2009-10-16 13:56 发表
查了一下,在compile kernel的时候有一个memory splict的选项,
可以改变PAGE_OFFSET的值。可以查一下 /lib/modules/`uname -r`/build/.config里CONFIG_PAGE_OFFSET的值。


我也正纳闷,怎么vmalloc有1G以上,我这最多只能划到500M多
原来可以自己指定user/kernel空间划分的,呵呵
学习了。
作者: eexplorer    时间: 2009-10-16 14:41
标题: 回复 #26 platinum 的帖子
> 不知道这种代价到底有多大,对内存管理不熟悉,eexplorer 兄可否给我们讲一下

如果减少了线性映射空间,那么kernel可以直接使用memory,即slab, kmalloc可以使用的memory就会减少,多余的memory只能当多high mem来使用。
作者: Godbach    时间: 2009-10-16 14:59
原帖由 platinum 于 2009-10-16 13:07 发表

我用的是 32bit 虚拟机,里面运行的是 32bit linux 系统 gentoo
虚拟机分配了 1536MB 内存(宿主机 2GB)


总共2G的内存吗,给虚拟机分配那么多啊?
作者: epegasus    时间: 2009-10-16 15:47
标题: 回复 #20 peimichael 的帖子
为什么留了那个8M?是用户空间到内核空间做双映射用的吗?
作者: platinum    时间: 2009-10-16 15:48
原帖由 Godbach 于 2009-10-16 14:59 发表


总共2G的内存吗,给虚拟机分配那么多啊?

不是为了配合你做测试吗,临时修改了分配值
作者: Godbach    时间: 2009-10-16 15:52
标题: 回复 #35 platinum 的帖子
分配那么大的内存,宿主机还跑得动吗?
作者: eexplorer    时间: 2009-10-16 16:02
标题: 回复 #34 epegasus 的帖子
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts.  That means that
* any out-of-bounds memory accesses will hopefully be caught.
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason.
*/            
#define VMALLOC_OFFSET  (8 * 1024 * 1024)
作者: platinum    时间: 2009-10-16 16:23
原帖由 Godbach 于 2009-10-16 15:52 发表
分配那么大的内存,宿主机还跑得动吗?

vmalloc 之前没问题,之后宿主系统差点死掉
作者: Godbach    时间: 2009-10-16 16:43
标题: 回复 #38 platinum 的帖子
呵呵,是啊。看来分配给虚拟机的内存只是一个上限。实际没用那么多时,宿主机都还可以用。一下子用了1G多,宿主机就没有多少了。
作者: epegasus    时间: 2009-10-16 16:49
标题: 回复 #37 eexplorer 的帖子
eexplorer always make the code wonderful.

8M是不是有点大呢?为什么是8M不是4K?

是不是所有的物理地址都要先映射到内核地址空间才能分配给用户用?如果不是,

当物理内存太多了,那远多出896的物理内存是不是可以分配独立的用户空间?而这个物理空间是不是就是在内核地址空间之外的,那么这个用户空间里的值到内核空间的copy怎么做?

----

哦,直接copy就可以了

[ 本帖最后由 epegasus 于 2009-10-16 16:53 编辑 ]
作者: eexplorer    时间: 2009-10-16 17:13
标题: 回复 #40 epegasus 的帖子
> 是不是所有的物理地址都要先映射到内核地址空间才能分配给用户用?

不是,线性映射的0-896M空间是预先映射好的,kernel可以随时access这些memory。
而high memory的话,kernel必须首先把它们map到自己的空间,得到kernel virtual address才能访问这些memory。

但是分配给用户的话,只需要把这个page的physical page frame number写到相应的page table的pte entry里就行了。所以high memory的page是没有问题的。

> 如果不是,
> 当物理内存太多了,那远多出896的物理内存是不是可以分配独立的用户空间?
> 而这个物理空间是不是 就是在内核地址空间之外的,那么这个用户空间里的值到内核空间的copy
> 改怎么做?

kernel是直接使用user space virtual address来访问的,所以copy_from_user必须在user process context里执行,因为要用到这个user process的page table
作者: Godbach    时间: 2009-10-16 17:43
白金兄,你申请了内存之后,给所有内存赋值为0xff
  1.         memset(data, 0xff, 1024 * 1024 * 200);
复制代码

而不是清零,是不是有什么说法啊?
作者: platinum    时间: 2009-10-16 18:00
原帖由 Godbach 于 2009-10-16 17:43 发表
白金兄,你申请了内存之后,给所有内存赋值为0xff
        memset(data, 0xff, 1024 * 1024 * 200);
而不是清零,是不是有什么说法啊?

没有,只是个人习惯问题
因为内存一般意义上讲,如果未被使用过,分配到以后内容是 0x00,我全写 0xff,以确保那段空间是可操作的
作者: Godbach    时间: 2009-10-16 18:09
标题: 回复 #43 platinum 的帖子
哦,我的做法通常是清零。
作者: Godbach    时间: 2009-10-16 18:51
标题: 回复 #43 platinum 的帖子
白金兄,还有通过vmalloc=xxx给内核传参数时,大小不能超过物理内存吧。
作者: platinum    时间: 2009-10-16 19:11
原帖由 Godbach 于 2009-10-16 18:51 发表
白金兄,还有通过vmalloc=xxx给内核传参数时,大小不能超过物理内存吧。

我也说不清,在我的虚拟机里可以,设成 4096M 都没问题,找了一个真实机器试却不行
另外发现还与内核参数有关,就是 HIGHMEM、1G/3G 那些,我设置的是 2G/2G
作者: xxxx486    时间: 2009-10-19 10:37
标题: 开源软件不是这样用的!
开源的,读读源代码就知道了。
作者: Godbach    时间: 2009-10-20 13:15
原帖由 platinum 于 2009-10-16 15:48 发表

不是为了配合你做测试吗,临时修改了分配值


白金兄你在内核引导菜单中怎么改的啊,我加了个vmalloc=1024M 结果不能引导了,改成vmalloc=800M, kernel panic了
作者: 6093151    时间: 2014-01-07 18:00
同求啊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。我也遇到了这问题
作者: embeddedlwp    时间: 2014-01-07 19:01
有一种不是很可靠的方法叫CMA. 另外可以参考hugetlb是怎样通过启动参数将各种大小的大页保留到自己的pool中的。




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