描述
Linux操作系统使用一种称为按需分页(Demand Paging)的内存管理策略。这种策略的主要思想是只有当程序真正需要使用某段内存时,才会将这段内存分配给程序。当程序请求分配内存时(比如通过malloc函数),操作系统并不会立即为其分配物理内存,而是先在虚拟地址空间中“预留”一块区域,等到程序真正访问这块内存时(比如通过读写操作),才会将物理内存分配给它。
具体表现为当使用malloc申请内存时,如果部队申请到的内存作操作则不会为其分配物理内存,测试code如下;每次申请8M内存,打印VSS和RSS
#include<stdio.h>
#include<unistd.h>
#include<malloc.h>
#include<fstream>
#include<iostream>
void process_mem_usage(double & vm_usage, double & resident_set)
{
std::ifstream stat("/proc/self/stat", std::ios::in);
// dummy vars for leading entries in stat that we don't care about
std::string pid, comm, state, ppid, pgrp, session, tty_nr;
std::string tpgid, flags, minflt, cminflt, majflt, cmajflt;
std::string utime, stime, cutime, cstime, priority, nice;
std::string O, itrealvalue, starttime;
// the two fields we want
unsigned long vsize;
long rss;
stat >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
>> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
>> utime >> stime >> cutime >> cstime >> priority >> nice
>> O >> itrealvalue >> starttime >> vsize >> rss;
vm_usage = vsize;
resident_set = rss * sysconf(_SC_PAGE_SIZE);
}
void print_mem_usage(const char* desc)
{
double vm_usage, resident_set;
process_mem_usage(vm_usage, resident_set);
std::cout << desc <<": "
<< "VSS: " << vm_usage / (1024*1024) << " MiB, "
<< "RSS: " << resident_set / (1024*1024) << " MiB" << std::endl;
}
void func(bool malloc_only = true)
{
std::string desc = malloc_only?"malloc only":"malloc after use";
size_t mall_size = 8*1024*1024; // 8M
for(int i=0; i<20; ++i)
{
char * x = (char *)malloc(mall_size);
if(!malloc_only)
{
for(int i=0; i<mall_size; ++i)
x[i] = 'c';
}
print_mem_usage(desc.c_str());
usleep(100000);
}
}
int main()
{
func(false);
return 0;
}
只申请不使用
申请后使用
优缺点
当不对申请到的内存作操作的时候,操作系统不会立即给进程分配物理内存。这种管理方式的优点在于,它可以帮助节省物理内存,提高内存的利用效率。因为在许多情况下,程序并不会使用到所有的内存;不过这种策略最主要的缺点就是可能会引发页面错误(Page Fault)。当程序试图访问的内存还没有被加载到物理内存中时,就会触发页面错误。处理页面错误需要花费一定的时间,这会降低程序的运行速度。