Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C mmap/munmap存在问题-在第783次迭代后出现总线错误?_C_Linux_Memory Management - Fatal编程技术网

C mmap/munmap存在问题-在第783次迭代后出现总线错误?

C mmap/munmap存在问题-在第783次迭代后出现总线错误?,c,linux,memory-management,C,Linux,Memory Management,好的,设置如下:我在HPC工作,我们正在准备扩展到数万个节点。为了解决这个问题,我实现了一个本地进程,它在每个节点上缓存信息,以减少网络流量。然后,它通过共享内存公开这些信息。基本逻辑是,有一个众所周知的共享内存块,其中包含当前缓存表的名称。当更新发生时,缓存工具创建一个新的共享内存表,填充它,然后用新表的名称更新已知的块 代码似乎正在运行查找(例如valgrind说没有内存泄漏),但当我故意对其进行压力测试时,第一个783更新工作得非常好-但在第784次,当我尝试写入映射内存时,我收到一个SI

好的,设置如下:我在HPC工作,我们正在准备扩展到数万个节点。为了解决这个问题,我实现了一个本地进程,它在每个节点上缓存信息,以减少网络流量。然后,它通过共享内存公开这些信息。基本逻辑是,有一个众所周知的共享内存块,其中包含当前缓存表的名称。当更新发生时,缓存工具创建一个新的共享内存表,填充它,然后用新表的名称更新已知的块

代码似乎正在运行查找(例如valgrind说没有内存泄漏),但当我故意对其进行压力测试时,第一个783更新工作得非常好-但在第784次,当我尝试写入映射内存时,我收到一个SIGBUS错误

如果问题是打开的文件太多(因为我泄漏了文件描述符),我希望shm_open()会失败。如果问题是我泄漏了映射内存,那么我希望mmap()失败,或者valgrind报告泄漏

这是代码片段。有人能提个建议吗

int
initialize_paths(writer_t *w, unsigned max_paths)
{
int err = 0;
reader_t *r = &(w->unpublished);

close_table(r,PATH_TABLE);

w->max_paths = max_paths;

err = open_table(r, PATH_TABLE, O_RDWR | O_CREAT, max_paths, 0);

return err;
}

static void
close_table(reader_t *r, int table)
{
    if (r->path_table && r->path_table != MAP_FAILED) {
       munmap(r->path_table,r->path_table->size);
       r->path_table=NULL;
    }
    if (r->path_fd>0) { close(r->path_fd); r->path_fd=0; }
}


static int
open_table(op_ppath_reader_t *r, int table, int rw, unsigned c, unsigned c2)
{
// Code omitted for clarity
if (rw & O_CREAT) {
    prot = PROT_READ | PROT_WRITE;
} else {
    // Note that this overrides the sizes set above.
    // We will get the real sizes from the header.
    prot = PROT_READ;
    size1 = sizeof(op_ppath_header_t);
    size2 = 0;
}

fd = shm_open(name, rw, 0644);
if (fd < 0) {
    _DBG_ERROR("Failed to open %s\n",name);
    goto error;
}

if (rw & O_CREAT) {
    /* Create the file at the specified size. */
    if (ftruncate(fd, size1 + size2)) {
        _DBG_ERROR("Unable to size %s\n",name);
        goto error;
    }
}

h = (op_ppath_header_t*)mmap(0, size1 + size2, prot, MAP_SHARED, fd, 0);
if (h == MAP_FAILED) {
    _DBG_ERROR("Unable to map %s\n",name);
    goto error;
}

if (rw & O_CREAT) {
    /*
     * clear the table & set the maximum lengths.
     */
    memset((char*)h,0,size1+size2);  -- SIGBUS OCCURS HERE
    h->s1 = size1;
    h->s2 = size2;
} else {
// more code omitted for clarity.
}
以下是与上一次迭代相同的输出:

NOTICE: Pass 782: Inserting records.
NOTICE: Creating the path table.
TRC: initialize_paths[
TRC: close_table[
TRC: close_table]
TRC: open_ppath_table[
DBG: h=0x0x2a956b2000, size1=2621536, size2=0
TRC: open_ppath_table]
TRC: op_ppath_initialize_paths]
请注意,指针地址和大小都是有效的

GDB通过以下方式报告崩溃:

Program received signal SIGBUS, Bus error.
[Switching to Thread 182895447776 (LWP 5328)]
0x00000034a9371d20 in memset () from /lib64/tls/libc.so.6
(gdb) where
#0  0x00000034a9371d20 in memset () from /lib64/tls/libc.so.6
#1  0x0000002a955949d0 in open_table (r=0x7fbffff188, table=1, rw=66,
c=32768, c2=0) at ofedplus_path_private.c:294
#2  0x0000002a95595280 in initialize_paths (w=0x7fbffff130,
    max_paths=32768) at path_private.c:567
#3  0x0000000000402050 in server (fname=0x7fbffff270 "gidtable", n=10000)
    at opp_cache_test.c:202
#4  0x0000000000403086 in main (argc=6, argv=0x7fbffff568)
    at opp_cache_test.c:542
(gdb)


当在下一行上设置h->size1时,删除memset仍然会导致SIGBUS,而size1是映射区域的前4个字节。

可能是由于对SHM对象的多次引用导致SIGBUS。
查看上面的代码,您使用了shm_open()mmap()munmap(),但是
您缺少shm\u unlink()

由于*shm_open/shm_close的手册页说明这些对象是参考计数的

shm_unlink的操作类似于unlink(2):它删除共享内存对象 名称,并在所有进程取消映射对象后,取消分配和销毁 关联内存区域的内容。
成功shm\u取消链接后,尝试shm\u打开具有相同属性的对象 名称将失败(除非指定了O_create,在这种情况下,将创建一个新的、不同的对象)


此信息可能有助于解决您的问题。

O_CREAT案例的size1和size2的值是多少?您是否可以使用gdb(例如,在批处理模式下)对此代码进行压力测试,在memset调用之前放置一个断点以打印h的值,然后继续?如果它在gdb中运行正常,则可能是内存泄漏/缓冲区外写入。在本例中,size1大约为256k。对于压力测试,它的大小总是一样的。我已经知道shm_unlink(),并且我在不同的环境中使用它,但是你的建议让我重新检查了代码,并且我发现,事实上,旧数据从未被解除链接。我猜我实际上耗尽了Linux一次可以拥有的共享内存区域的数量。
Program received signal SIGBUS, Bus error.
[Switching to Thread 182895447776 (LWP 5328)]
0x00000034a9371d20 in memset () from /lib64/tls/libc.so.6
(gdb) where
#0  0x00000034a9371d20 in memset () from /lib64/tls/libc.so.6
#1  0x0000002a955949d0 in open_table (r=0x7fbffff188, table=1, rw=66,
c=32768, c2=0) at ofedplus_path_private.c:294
#2  0x0000002a95595280 in initialize_paths (w=0x7fbffff130,
    max_paths=32768) at path_private.c:567
#3  0x0000000000402050 in server (fname=0x7fbffff270 "gidtable", n=10000)
    at opp_cache_test.c:202
#4  0x0000000000403086 in main (argc=6, argv=0x7fbffff568)
    at opp_cache_test.c:542