以下是一个小程序,它使用MMAP"分配" 20GB虚拟地址空间,然后是segfaults。可以独立控制两种行为(通过CMD线参数):第一个行为导致应用程序实际写入20GB的每个行为;第二个导致应用程序在启动上产生pthread。因此,可以通过四种方式运行该程序。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <pthread.h>
#define DELAY 3
#define THREAD_DELAY 1
#define TIMES 20
#define GB 1024*1024*1024
void* thread_run(void* name){
while(1){
sleep(THREAD_DELAY);
}
}
void thread_start(char* name) {
pthread_t thread;
int ret;
ret = pthread_create(&thread, NULL, thread_run, (void*)name);
if(ret){
printf("failure spawing thread [%d]n", ret);
exit(-1);
}
}
int write_to_memory = 0;
int start_thread = 0;
int main(int argc, char** argv){
int i;
void** address_array = malloc(TIMES * sizeof(void*));
int* ptr = (int*)0;
printf("PID is %dn", getpid());
for(i = 0; i < argc; i++){
if(strcmp(argv[i], "write_to_memory") == 0) write_to_memory = 1;
if(strcmp(argv[i], "start_thread") == 0) start_thread = 1;
}
printf("write_to_memory = %dn", write_to_memory);
printf("start_thread = %dn", start_thread);
if(start_thread){
thread_start("OTHER_THREAD");
}
sleep(DELAY);
for(i = 0; i < TIMES; i++){
address_array[i] = mmap(NULL, GB, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(address_array[i] == MAP_FAILED){
printf("mmap failed");
exit(-2);
}
}
if(write_to_memory){
sleep(DELAY);
for(i = 0; i < TIMES; i++){
memset(address_array[i], 0, GB);
}
}
sleep(DELAY);
*ptr = 123;
return *ptr;
}
运行该程序的所有四种方式,我看到了一些非常奇怪的东西 - 对于可以运行程序的四种方式中的三种,核心转储的尺寸将约为20 GB;但是,如果我产生线程,但不要写入分配的内存,则核心转储的大小仅为11 MB。我无法解释这种行为,并且想知道是否可以预期。
首先,有关环境的一些细节:
[user@machine coredump]$ uname -a
Linux machine.domain 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
[user@machine coredump]$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
[user@machine coredump]$ /lib/libc.so.6
GNU C Library stable release version 2.12, by Roland McGrath et al.
Native POSIX Threads Library by Ulrich Drepper et al
现在输出
_____________________
PID is 16012
write_to_memory = 0
start_thread = 0
Segmentation fault (core dumped)
-rw------- 1 user group 21G Mar 14 22:57 core.16012
_____________________
PID is 16201
write_to_memory = 0
start_thread = 1
Segmentation fault (core dumped)
-rw------- 1 user group 11M Mar 14 22:57 core.16201
_____________________
PID is 16234
write_to_memory = 1
start_thread = 0
Segmentation fault (core dumped)
-rw------- 1 user group 21G Mar 14 22:58 core.16234
_____________________
PID is 16425
write_to_memory = 1
start_thread = 1
Segmentation fault (core dumped)
-rw------- 1 user group 21G Mar 14 22:59 core.16425
这是预期的行为吗?如果是这样,使用Pthreads是否暗示有一个"智能"默认的segfault处理程序,它意识到分配的内存尚未触摸,因此不需要倾倒?
map_anonymous的通用实现| map_private是创建一个潜在的映射,而不是真实的映射。潜在映射是从(逻辑上)/dev/Zero的模仿映射。无需创建它,因为它可以在零页面的任何时候创建。有时,首字母缩写词zerofillondemand与此
相关联一旦您为页面编写任何值,您的程序就会错误,并且将添加一个实际页面。此时,该页面的唯一来源是您的程序图像。因此,为了保存和/或重新使用快速公羊的系统可能将其存储在交换中;您的图像仍然是唯一的来源。
当涉及核心倾倒时,您的过程图像中通常有许多区域(段)由潜在的映射组成。例如,该堆栈通常是一个很大的区域,很少使用。Coredump明智地选择仅插入这些单源元素,并为其余的参考。
根据您的系统,您可能会注意到程序文本和共享库也不是您核心图像的一部分。通常,您可以通过在程序中仅找到读取字符串来对此进行测试,并使用strings core | fgrep 'your special string here'
搜索它。GetOpt()的字符串通常是一个很好的搜索候选者。