brk mmap
Both brk() and mmap() cause pages to be mapped into the process's address space. mmap() can be used to map pages of a file into memory, but it can also be used only to map pages, i.e., allocate memory. brk() is just a specific interface to the VM subsystem which maps pages at a specific location (top of heap). mmap() on the other hand lets you map any page (mostly) anywhere you want.
brk() could be implemented with mmap(), but not vice versa.
As for where the pages come from, that's up to the kernel. The process can decide which virtual address it wants mapped -- the kernel is responsible for allocating a physical page and mapping it where the process has requested.
mmap() is no better unless you really want to cater for the rather special case that you want to reduce the heap when it's got most of it's memory freed but a small section at the top end of the heap is occupied. The brk() model is perfectly fine for most purposes, as the heap will normally (in typical applications) grow to a certain size, and then either fluctuate a little bit up and down from that size, or grow and then shrink again. In the normal case for grow and shrink, it's mainly "newest allocations" being deallocated.
Also, if there are large "holes" in the heap, those areas are good candidates for swapping out to disk, as they will not be touched. So whilst it's taking up VIRTUAL memory space, it's not going to cause much of a problem in the physical memory (assuming there's a squeeze in the first place of course).
Oh, and by the way, memory allocated via brk() is most likely not committed until it's being written to, so if you allocate a large chunk of memoyr (using malloc() or close relatives), not all that memory will be used in physical memory until it's been "used" (read or written).
As matsp said, things get swapped out and don't cause a problem anyway. And if you really wanted to release memory inside the heap, nothing is stopping you from munmap()'ing it (aside from probably confusing the hell out of malloc()).
brk() is just an older, traditional way of obtaining more pages from the OS. I don't really think either one is "better" than the other.
草草的做个总结吧,然后去吃饭:
1,malloc 和 mmap 极其相似,它们俩都不消耗物理内存,但是如果物理内存有富余的话,就会给它们用。
2,当物理内存紧张时(比如别的程序又需要申请一大笔内存),就会换页,将暂时用不到的页面交换到磁盘上去。
malloc 是交换到 swap(包括 swap 分区和 swap file),但是 mmap 则是交换到文件里去。
推论:
1,swap 分区总是有限的,因此所有进程总共可以 malloc 的内存总是有限的,
但是 mmap 则只要磁盘空间足够,总是能成功,且不影响其它应用程序的正常运行(【重要】也就是不会随机 drop 倒霉进程)。
2,考虑只读的情况,mmap 不会比 malloc 更慢,因为它们俩的策略是相同的,都是优先使用物理内存,缺页时从磁盘上 load 页面。
out_of_memory的策略不知道
__alloc_pages 里面在一定条件下会调用 out_of_memory函数,它会根据一些策略选择要杀死的进程
to flw: 我的是1G的 swap我不知道,我没有使用swap,也没看过相关资料
我觉得先不用考虑swap. 一旦用户态进程缺页, 那么可能有很多原因,比如至少有如下的几个:
1. 访问的地址不属于用户空间(内核能得到出错的线性地址,然后得知),那么将得到一个SIGSVEG信号
2. 访问的地址属于用户空间,但是这个地址所在的页还没有分配页框(比如分配一个大数组,然后写就会遇到这个情况),那是要分配物理地址,然后让该进程的对应页表项更新,继续执行缺页代码,就不会再缺页了
3. 地址空间内,但是检查到被交换出去了? 然后调入,这同样需要分配物理内存
4. 其它
内核在分配内存的时候最底层的来自__alloc_pages, 这个函数肯定不一定能成功,在不成功的时候就可能会杀死进程, ULK上说了具体的步骤,分析了这个函数,这个函数也有人分析过,虽然步骤很多,但是分析后还是比代码强
Linux 允许所有的内存作file cache.
munmap 释放进程空间+物理内存。如果是匿名mmap,释放的物理内存在 "free -m" 的 "free" 列;如果是普遍文件mmap,释放的物理内存在 "free -m" 的 "cached" 列。cached memory 属准释放态物理内存。当系统的free memory list size小于pages_low,swap daemon启动,先偷换cached memory。
传统清除cache的方法是运行一个小程序,狂分配内存,迫使swap daemon偷换cached memory。程序退出,内存回到free list.
进程调用mmap()时,只是在进程空间内新增了一块相应大小的缓冲区,并设置了相应的访问标识,但并没有建立进程空间到物理页面的映射。因此,第一次访问该空间时,会引发一个缺页异常。