我写了一个简单的应用来测试内存消耗。在这个测试应用程序中,我创建了四个持续消耗内存的进程,除非进程退出,否则这些进程不会释放内存。
我希望这个测试应用程序占用大部分RAM内存并导致其他应用程序变慢或崩溃。但结果与预期不一样。以下是代码:
#include <stdio.h>
#include <unistd.h>
#include <list>
#include <vector>
using namespace std;
unsigned short calcrc(unsigned char *ptr, int count)
{
unsigned short crc;
unsigned char i;
//high cpu-consumption code
//implements the CRC algorithm
//CRC is Cyclic Redundancy Code
}
void* ForkChild(void* param){
vector<unsigned char*> MemoryVector;
pid_t PID = fork();
if (PID > 0){
const int TEN_MEGA = 10 * 10 * 1024 * 1024;
unsigned char* buffer = NULL;
while(1){
buffer = NULL;
buffer = new unsigned char [TEN_MEGA];
if (buffer){
try{
calcrc(buffer, TEN_MEGA);
MemoryVector.push_back(buffer);
} catch(...){
printf("An error was throwed, but caught by our app!\n");
delete [] buffer;
buffer = NULL;
}
}
else{
printf("no memory to allocate!\n");
try{
if (MemoryVector.size()){
buffer = MemoryVector[0];
calcrc(buffer, TEN_MEGA);
buffer = NULL;
} else {
printf("no memory ever allocated for this Process!\n");
continue;
}
} catch(...){
printf("An error was throwed -- branch 2,"
"but caught by our app!\n");
buffer = NULL;
}
}
} //while(1)
} else if (PID == 0){
} else {
perror("fork error");
}
return NULL;
}
int main(){
int children = 4;
while(--children >= 0){
ForkChild(NULL);
};
while(1) sleep(1);
printf("exiting main process\n");
return 0;
}
TOP命令
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2775 steve 20 0 1503m 508 312 R 99.5 0.0 1:00.46 test
2777 steve 20 0 1503m 508 312 R 96.9 0.0 1:00.54 test
2774 steve 20 0 1503m 904 708 R 96.6 0.0 0:59.92 test
2776 steve 20 0 1503m 508 312 R 96.2 0.0 1:00.57 test
虽然CPU很高,但内存百分比仍为0.0。怎么可能?
免费命令
free shared buffers cached
Mem: 3083796 0 55996 428296
4G RAM中的可用内存超过3G。
有没有人知道为什么这个测试应用程序没有按预期工作?
答案 0 :(得分:6)
Linux使用乐观内存分配:在实际写入该页面之前,它不会物理分配一页内存。因此,您可以分配比可用内存更多的内存,而不会增加系统的内存消耗。
如果要强制系统分配(提交)物理页面,则必须写入。
以下行不会发出任何 write ,因为它是unsigned char
的默认初始化,这是一个无操作:
buffer = new unsigned char [TEN_MEGA];
如果要强制提交,请使用零初始化:
buffer = new unsigned char [TEN_MEGA]();
答案 1 :(得分:3)
将评论作为答案:
unsigned char
does not perform any initializations的默认构造函数和new[]
默认初始化所有项目。答案 2 :(得分:1)
fork()
返回父级中的PID,并返回子级中的0。你写的ForkChild
将执行父母的所有工作,而不是孩子。
标准new
运算符永远不会返回null;如果它无法分配内存,它将抛出(但由于过度使用它在Linux中实际上不会这样做)。这意味着您在分配后对buffer
的测试毫无意义:它将始终采用第一个分支或永远不会到达测试。如果要返回null,则需要编写new (std::nothrow) ...
。包括<new>
以便工作。
答案 3 :(得分:0)
但是你的程序实际上正在做你期望它做的事情。正如答案所指出的那样(@ Michael Foukarakis的answer),未分配的内存未被分配。在top
程序的输出中,我注意到列virt
对于运行程序的每个进程都有大量内存。稍后有点谷歌搜索,我看到了这是:
VIRT - Virtual Memory Size (KiB). The total amount of virtual memory used by the task.
它包括所有代码,数据和共享库以及已换出的网页和已映射的网页 但未使用。
正如您所看到的,您的程序实际上确实为自己生成了内存,但是以页面的形式存储并存储为虚拟内存。而且我认为这是明智之举
的摘录页面,内存页面或虚拟页面 - 一个固定长度的连续虚拟内存块,它是最小的以下数据单位:
...因此,程序可以处理比计算机中实际存在的更多(虚拟)RAM。虚拟内存是一种方案,它为用户提供了处理大块连续内存空间(可能甚至比实际内存更大)的错觉,而实际上他们的大部分工作都在辅助存储(磁盘)上。根据需要,将作业的固定大小的块(页面)或可变大小的块读入主存储器。
<强>来源强>:
答案 4 :(得分:-1)
如果你想吞噬大量的记忆:
int mb = 0;
char* buffer;
while (1) {
buffer = malloc(1024*1024);
memset(buffer, 0, 1024*1024);
mb++;
}
我使用这样的东西来确保在进行一些文件I / O定时测量时文件缓冲区高速缓存是空的。
正如其他答案已经提到的那样,您的代码在分配后不会写入缓冲区。这里使用memset写入缓冲区。