我试图编写一个可以通过malloc(1024*1024*1024)
从系统获取1GB内存的程序。
获得内存的起始地址后,在我有限的理解中,如果我想初始化它,只需使用memset()
来实现。但事实是,一段时间后会触发段错误。
我尝试使用gdb查找导致它的原因,最后发现如果我执行一些内存操作超过128 MB 会导致此错误。
是否有任何规则限制程序只能访问小于128 MB的内存?或者我用错误的方式分配和初始化它?
如果需要其他信息,请告诉我。
任何建议都将受到赞赏。
[平台]
gcc test.c -o test
[代码]
size_t mem_size = 1024 * 1024 * 1024;
...
void *based = malloc(mem_size); //mem_size = 1024^3
int stage = 65536;
int initialized = 0;
if (based) {
printf("Allocated %zu Bytes from %lx to %lx\n", mem_size, based, based + mem_size);
} else {
printf("Error in allocation.\n");
return 1;
}
int n = 0;
while (initialized < mem_size) { //initialize it in batches
printf("%6d %lx-%lx\n", n++, based+initialized, based+initialized+stage);
memset(based + initialized, '$', stage);
initialized += stage;
}
[结果]
Allocated 1073741824 Bytes from 7f74c9e66010 to 7f76c9e66010
...
2045 7f7509ce6010-7f7509d66010
2046 7f7509d66010-7f7509de6010
2047 7f7509de6010-7f7509e66010
2048 7f7509e66010-7f7509ee6010 //2048*65536(B)=128(MB)
Segmentation fault (core dumped)
答案 0 :(得分:2)
这里有两个可能的问题。首先,您没有正确使用malloc()
。您需要检查它是否返回NULL
或非NULL
值。
另一个问题可能是操作系统过度提交内存,而内存不足(OOM)杀手正在终止你的进程。 You can disable over-committing of memory and getting dumps to detect via these instructions.
两个主要问题:
n++
)。非常糟糕的做法,因为日志调用通常在大型项目的编译时被删除,现在程序的行为也不同。based
投放到(char *)
。这应该有助于解决您的问题。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
size_t mem_size = 1024 * 1024 * 1024;
printf("MEMSIZE: %lu\n", mem_size);
printf("SIZE OF: void*:%lu\n", sizeof(void*));
printf("SIZE OF: char*:%lun", sizeof(char*));
void *based = malloc(mem_size); //mem_size = 1024^3
int stage = 65536;
int initialized = 0;
if (based) {
printf("Allocated %zu Bytes from %p to %p\n", mem_size, based, based + mem_size);
} else {
printf("Error in allocation.\n");
return 1;
}
int n = 0;
while (initialized < mem_size) { //initialize it in batches
//printf("%6d %p-%p\n", n, based+initialized, based+initialized+stage);
n++;
memset((char *)based + initialized, '$', stage);
initialized += stage;
}
free(based);
return 0;
}
答案 1 :(得分:-1)
神圣,我发现问题 - 指针类型出错了。
这是完整的代码
int main(int argc, char *argv[]) {
/*Allocate 1GB memory*/
size_t mem_size = 1024 * 1024 * 1024;
// the problem is here, I used to use pointer as long long type
char* based = malloc(mem_size);
// and it misleading system to calculate incorrect offset
if (based) {
printf("Allocated %zu Bytes from %lx to %lx\n", mem_size, based, based + mem_size);
} else {
printf("Allocation Error.\n");
return 1;
}
/*Initialize the memory in batches*/
size_t stage = 65536;
size_t initialized = 0;
while (initialized < mem_size) {
memset(based + initialized, '$', stage);
initialized += stage;
}
/*And then I set the breakpoint, check the memory content with gdb*/
...
return 0;
感谢那些给我建议或意见的人:)
答案 2 :(得分:-2)
进程需要如此大量的连续内存是非常罕见的,是的,内核确实强加了这样的内存限制。在处理大于128 Kb的内存请求时,您可能应该知道malloc()
它在窗帘后面调用mmap()
。你应该尝试直接使用它。
您还应该知道分配时内核的默认策略是分配比它更多的内存。 逻辑是大多数已分配的内存实际上并未使用,因此允许超出系统实际内存的分配相对安全。
编辑:正如有些人所指出的那样,当你的进程开始使用内核成功分配的内存时,它将被OOM Killer杀死。此代码生成了以下输出:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int arc, char**argv)
{
char *c = malloc(sizeof(char) * 1024 * 1024 * 1024 * 5);
if(c)
{
printf("allocated memory\n");
memset(c, 1, sizeof(char) * 1024 * 1024 * 1024 * 5);
free(c);
}
else
{
printf("Out of memory\n");
}
return 0;
}
输出:
$ ./a.out
allocated memory
Killed
但在更改系统限制后:
# echo 2 > /proc/sys/vm/overcommit_memory
# exit
exit
$ ./a.out
Out of memory
如您所见,内存分配在系统上成功,问题仅在使用内存后才出现 的:修改
内核限制你可以分配多少内存,你可以使用这些命令检查它们:
grep -e MemTotal -e CommitLimit -e Committed_AS /proc/meminfo
ulimit -a
第一个命令将打印总内存,第二个命令将显示内核对分配的限制(CommitLimit)。该限制基于您的系统内存和系统上定义的超额提交率,您可以使用此命令cat /proc/sys/vm/overcommit_ratio
进行检查。
Committed_AS是目前已分配给系统的内存。您会注意到这可能超过总内存而不会导致崩溃。
通过编写echo 2 > /proc/sys/vm/overcommit_memory
,您可以将内核的默认行为更改为永不过量使用。您可以查看手册页以获取有关此内容的更多信息。
我建议检查系统上的限制,然后禁用内核的默认过度使用行为。然后通过在分配时检查malloc()
mmap()
是否失败来尝试查看您的系统是否实际分配了那么多内存。
来源:LSFMM: Improving the out-of-memory killer 和掌握嵌入式Linux编程 Chris Simmonds