在Linux系统中程序的内存空间一般被划分成两个区域: 栈空间和堆空间(其他空间区域本文不做讨论):
- 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
- 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
堆上申请空间我们并不陌生,但是对于栈上申请空间我们一直认为那是操作系统的事情,我们不需要去参与。其实Linux的C库中有这么一个函数,就是让程序员在栈空间申请内存的:alloca是向栈申请内存,因此无需释放. 那问题来了,我们可以通过这个函数在程序里申请多大的空间?
函数的参数是可以填写任意大小的数字,但是实际控制是受限于程序的栈空间的可用空间的大小的。在Linux里面每个程序都有一个程序的栈空间的,这个值是一个可配置的系统参数,我们可以通过命令或者函数查看和修改的:
struct rlimit lmt;
getrlimit(RLIMIT_STACK, &lmt);
printf("rlim_cur=%u, rlim_max=%u\n", lmt.rlim_cur, lmt.rlim_max);
在我的系统中输出为:rlim_cur=8388608, rlim_max=4294967295
从上的命令行和程序代码都输出的是缺省的8M的栈空间。所以如果我们用alloca函数在栈上申请一个很大的空间的话,应该就会发生栈越界等内存异常的程序崩溃现象。
那如果我们想修改这个缺省的8M的栈空间的限制,我们要怎么做呢?
- 通过命令行修改整个系统,让每个程序的栈空间都变大:堆栈大小:ulimit -s unlimited
- 通过函数在程序里面修改该本程序的栈空间:
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *new_limit,
struct rlimit *old_limit);
resource:可能的选择有
RLIMIT_AS //进程的最大虚内存空间,字节为单位。
RLIMIT_CORE //内核转存文件的最大长度。
RLIMIT_CPU //最大允许的CPU使用时间,秒为单位。当进程达到软限制,内核将给其发送SIGXCPU信号,这一信号的默认行为是终止进程的执行。然而,可以捕捉信号,处理句柄可将控制返回给主程序。如果进程继续耗费CPU时间,核心会以每秒一次的频率给其发送SIGXCPU信号,直到达到硬限制,那时将给进程发送 SIGKILL信号终止其执行。
RLIMIT_DATA //进程数据段的最大值。
RLIMIT_FSIZE //进程可建立的文件的最大长度。如果进程试图超出这一限制时,核心会给其发送SIGXFSZ信号,默认情况下将终止进程的执行。
RLIMIT_LOCKS //进程可建立的锁和租赁的最大值。
RLIMIT_MEMLOCK //进程可锁定在内存中的最大数据量,字节为单位。
RLIMIT_MSGQUEUE //进程可为POSIX消息队列分配的最大字节数。
RLIMIT_NICE //进程可通过setpriority() 或 nice()调用设置的最大完美值。
RLIMIT_NOFILE //指定比进程可打开的最大文件描述词大一的值,超出此值,将会产生EMFILE错误。
RLIMIT_NPROC //用户可拥有的最大进程数。
RLIMIT_RTPRIO //进程可通过sched_setscheduler 和 sched_setparam设置的最大实时优先级。
RLIMIT_SIGPENDING //用户可拥有的最大挂起信号数。
RLIMIT_STACK //最大的进程堆栈,以字节为单位。
rlim:描述资源软硬限制的结构体,原型如下
struct rlimit {
rlim_t rlim_cur;
rlim_t rlim_max;
};
返回说明:成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EFAULT:rlim指针指向的空间不可访问
EINVAL:参数无效
EPERM:增加资源限制值时,权能不允许
在实际的实践中,一般不建议程序员去修改栈的空间大小,如果非要修改,最好在自己的程序里面修改就行了,不要去修改整个系统的。因为栈空间是在程序启动的那一刻就已经从系统中分配走的一块空间,太大的值会导致系统内存严重浪费的情况的。