一 物理内存和虚拟内存
我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念。
物理内存就是系统硬件提供的内存大小,是真正的内存,相对于物理内存,在linux下还有一个虚拟内存的概念,虚拟内存就是为了满足物理内存的不足
Linux的内存管理采取的是分页存取机制,为了保证物理内存能得到充分的利用,内核会在适当的时候将物理内存中不经常使用的数据块自动交换到虚拟内存中,而将经常使用的信息保留到物理内存。
要深入了解linux内存运行机制,需要知道下面提到的几个方面:
Linux系统会不时的进行页面交换 *** 作,以保持尽可能多的空闲物理内存,即使并没有什么事情需要内存,Linux也会交换出暂时不用的内存页面。这可以避免等待交换所需的时间。
Linux 进行页面交换是有条件的,不是所有页面在不用时都交换到虚拟内存,linux内核根据”最近最经常使用“算法,仅仅将一些不经常使用的页面文件交换到虚拟 内存,有时我们会看到这么一个现象:linux物理内存还有很多,但是交换空间也使用了很多。其实,这并不奇怪,例如,一个占用很大内存的进程运行时,需 要耗费很多内存资源,此时就会有一些不常用页面文件被交换到虚拟内存中,但后来这个占用很多内存资源的进程结束并释放了很多内存时,刚才被交换出去的页面 文件并不会自动的交换进物理内存,除非有这个必要,那么此刻系统物理内存就会空闲很多,同时交换空间也在被使用,就出现了刚才所说的现象了。关于这点,不 用担心什么,只要知道是怎么一回事就可以了。
交换空间的页面在使用时会首先被交换到物理内存,如果此时没有足够的物理内存来容纳这些页 面,它们又会被马上交换出去,如此以来,虚拟内存中可能没有足够空间来存储这些交换页面,最终会导致linux出现假死机、服务异常等问题,linux虽 然可以在一段时间内自行恢复,但是恢复后的系统已经基本不可用了。
因此,合理规划和设计Linux内存的使用,是非常重要的.
二 内存的监控
作为一名Linux系统管理员,监控内存的使用状态是非常重要的,通过监控有助于了解内存的使用状态,比如内存占用是否正常,内存是否紧缺等等,监控内存最常使用的命令有free、top等
有两种方法可以解决这个问题1、如果可能,请升级到64位系统。
这是最好的解决办法,因为所有的内存都将成为low memory。如果你在这种情况下耗尽了low memory,那就真的是out of memory了。
2、如果受限于必须使用32位系统,最好的解决办法是使用hugemem内核。
这种内核以不同的方式分割low/high memory,而且在大多数情况下会提供足够多的low memory到high memory的映射。在大多数案例中,这是一个很简单的修复方法:安装hugemem kernel RPM包,然后重启即可。
如果运行hugemem内核也不可能,你可以尝试将/proc/sys/vm/lower_zone_protection 的值设置为250甚至更多。这将让内核愿意保护low memory,从而在分配内存时多考虑从high memory分配。据我所知,此选项从2.6.x内核才开始可用。必要的是,您可能需要通过一些实验来找到您系统环境中最适合的值。可以使用下面方法快速的设置和检查改值:
# cat /proc/sys/vm/lower_zone_protection
# echo "250" >/proc/sys/vm/lower_zone_protection
在 /etc/sysctl.conf 中加入设置,以便启动就生效:
vm.lower_zone_protection = 250
作为最后的努力,你可以关闭oom-killer。这个选项可以导致系统挂起,所以请小心使用(风险自负)!
查看当前oom-killer的状态:
# cat /proc/sys/vm/oom-kill
关闭/打开oom-killer:
# echo "0" >/proc/sys/vm/oom-kill
# echo "1" >/proc/sys/vm/oom-kill
当进程该被oom-killer杀死却没有被杀死时,相关信息会记录到 /var/log/messages:
"Would have oom-killed but /proc/sys/vm/oom-kill is disabled"
常用的IPC机制:1.mmap 共享内存
2.管道方式
mmap 方式申请一段连续的地址,听过修改页表,将2个进程的虚拟地址映射打同一个物理地址,达到共享的目的。
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags,
int fd, off_t offset)
int munmap(void *start, size_t length)
编辑本段参数start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。
length:映射区的长度。
prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起
PROT_EXEC //页内容可以被执行
PROT_READ //页内容可以被读取
PROT_WRITE //页可以被写入
PROT_NONE //页不可访问
flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用, *** 作将会失败。并且起始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1。
offset:被映射对象内容的起点。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)