我有一个服务器进程,它使用System共享内存调用(shmget/shmat)分配一大块内存,从address到0x500000000到0x1d00000000,然后将其绑定到第一个NUMA节点。请参阅下面的伪代码(它在逻辑上应该是正确的,但可能无法编译)。
问题是,有时当我访问内存时,我会得到一个SIGBUS信号,但大多数时候我没有,它大部分时间都能工作。我使用信号处理程序来优雅地捕获信号(也包括SIGSEGV )。
我不明白这是怎么回事。什么会导致SIGBUS的不稳定?
size_t totalSize_ = 96 GiB;
const int flags = IPC_CREAT // creatE a new shared memory segment
| SHM_HUGETLB // huge pages
| SHM_NORESERVE // don't reserve swap space for this.
| 0666 // Leave the leading 0 (octal)
| SHM_R | SHM_W // These are redundant with 0666
;
shmid_ = shmget(key_, totalSize_, flags);
void* desiredBase = 0x0x500000000;
auto base = shmat(shmid_, desiredBase, 0);
uint32_t mask = 1; // first NUMA node
mbind(base , totalSize_ , MPOL_BIND, &mask, 64, 0) ;然后,我做了一些测试,以确保内存是可访问的(因为NUMA绑定),方法是逐步遍历地址空间并调用memcpy每个GiB。
for(addr = base; addr < last, addr += 1GiB)
memcpy(addr, "testpattern",10);然后我寻找SIGBUS信号。如果NUMA节点没有足够大的页面内存分配给它,我会得到SIGBUS信号。这很好。但是,如果我用相同的代码和设置重新启动服务器,有时它会在第3大页上给我一个SIGBUS。然后我再重新启动它,它对所有96个巨大的页面都很好。我们的系统每个NUMA节点(4个节点)有100 GiB的巨大页面内存。
我如何调试这个?哪些日志文件是有用的?在memcpy上添加一个重试循环直到SIGBUS消失是否有意义?
/proc/self/maps的第一部分如下所示:
00400000-01213000 r-xp 00000000 103:07 4986562 /opt/daemon-0.0.9/bin/daemon
01413000-01415000 r-xp 00e13000 103:07 4986562 /opt/daemon-0.0.9/bin/daemon
01415000-0141b000 rwxp 00e15000 103:07 4986562 /opt/daemon-0.0.9/bin/daemon
0141b000-01427000 rwxp 00000000 00:00 0
01b5d000-01bfa000 rwxp 00000000 00:00 0 [heap]
500000000-1d00000000 rwxs 00000000 00:0d 44072961 /SYSV50420051 (deleted)
2aaac0000000-2aab00000000 rwxp 00000000 00:0d 83594486 /anon_hugepage (deleted)
7ff9e4000000-7ff9e4021000 rwxp 00000000 00:00 0
7ff9e4021000-7ff9e8000000 ---p 00000000 00:00 0发布于 2022-05-05 03:02:35
你的旗帜中的SHM_NORESERVE可能是罪魁祸首。来自the docs for shmget()
不为此段保留交换空间。当预留交换空间时,可以保证可以修改段。当交换空间没有保留时,如果没有可用的物理内存,则如果没有可用的物理内存,则可能在写入时获得
SIGSEGV。
(强调后加)
段创建、绑定和后续访问通常工作,这一事实表明了某种上下文效应,例如当前可用物理内存的数量,而使用该标志创建段的风险中明显存在分段错误。
SIGSEGV与SIGBUS并不完全相同,但两者都是在类似的情况下生成的。
https://stackoverflow.com/questions/71850463
复制相似问题