1
wayslog 2016-10-09 11:50:34 +08:00
那个……老兄……你开了多少线程……没记错的话,每个线程默认会分配 8M 的空间。而且,线程过多其实并不是一件好事儿, IO bound 的话考虑开核心数量的 2x 到 4x , CPU bound 的话干脆开 1x 就行……
|
2
ryd994 2016-10-09 12:20:35 +08:00 via Android
虚拟内存不一定占用物理内存,不说 swap , mmap 也是计入的。
不过如果是内存不足的话应该会 oom 异常。 segfault 建议还是先查内存 bug ,上 valgrind 有可能是多线程有 bug 啊,特别是竞态导致超预期数据 |
3
algas OP |
4
algas OP @ryd994
感觉上更像是 stack 之类的爆了,说实话我对这个不太了解,但是我已经完全手动申请释放内存了。 异常退出的部分没有申请内存,多线程部分只是计算不同序列的平均值之类的东西,读写都是不同位置的内存。 这个程序是同样使用 40 线程计算小一点的系统是完全正常的,不像存在内存泻露的样子。 另外就是,小规模情况下没有问题,出现问题的计算规模都要占用一半以上的物理内存, valgrind 是不是没有办法对付这种情况? |
5
ryd994 2016-10-09 13:04:31 +08:00 via Android
|
6
icylord 2016-10-09 13:13:33 +08:00
排除代码 bug 了嘛
|
7
reus 2016-10-09 13:27:51 +08:00
用 rust 写就没有 segfault 了,理论上
|
9
wayslog 2016-10-09 13:38:55 +08:00
@reus 我们不排除 segfault ,该爆栈还是要爆,但是 rust 的极小 runtime 会拦截这些 segfault ,改成 panic ,能更好的 debug 。
另外上一个提问的安全解答是: let mut v = box [1u8; 1024*1024*1024*4+1]; |
10
algas OP @ryd994
我尝试一下。 @icylord 之前都已经在用来出结果了,最近找了个配置很好的机器,才发现这种问题。 编译参数: g++ -O3 -fopenmp -mavx -mfma -fPIC --share -g -I ./ testa.cpp -o libtesta.so gcc basic/*.c *.c -O3 -DSFMT_MEXP=19937 -lpthread -lm -Wall -fopenmp -mavx -mfma -L ./ -ltesta -Wl,-rpath=. C 和 C++混编,但是程序还没有进入到 c++的库就退出了。 |
11
xiaozhaoz 2016-10-09 14:06:19 +08:00
确认系统 /proc/sys/vm/overcommit_* 设置。
overcommit* 控制了进程占用虚拟空间 和 系统物理内存的关系。 |
12
xiaozhaoz 2016-10-09 14:09:26 +08:00
cat /proc/meminfo , 贴出来看看
|
13
algas OP @xiaozhaoz
这 overcommnit_*文件如下,这个完全不明白是什么意思。 [14:08]:ls /proc/sys/vm/overcommit_* /proc/sys/vm/overcommit_kbytes /proc/sys/vm/overcommit_memory /proc/sys/vm/overcommit_ratio cat /proc/sys/vm/overcommit_* 0 0 50 |
14
algas OP @xiaozhaoz
[14:10]:cat /proc/meminfo MemTotal: 131915360 kB MemFree: 131296756 kB MemAvailable: 131385392 kB Buffers: 20536 kB Cached: 173024 kB SwapCached: 0 kB Active: 151716 kB Inactive: 104916 kB Active(anon): 63772 kB Inactive(anon): 2520 kB Active(file): 87944 kB Inactive(file): 102396 kB Unevictable: 68 kB Mlocked: 68 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 0 kB Writeback: 0 kB AnonPages: 63200 kB Mapped: 53380 kB Shmem: 3200 kB Slab: 72120 kB SReclaimable: 26112 kB SUnreclaim: 46008 kB KernelStack: 10416 kB PageTables: 5484 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 65957680 kB Committed_AS: 151684 kB VmallocTotal: 34359738367 kB VmallocUsed: 499908 kB VmallocChunk: 34291843068 kB HardwareCorrupted: 0 kB AnonHugePages: 10240 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 891976 kB DirectMap2M: 103849984 kB DirectMap1G: 31457280 kB |
15
xiaozhaoz 2016-10-09 14:19:46 +08:00
CommitLimit: 65957680 kB
Committed_AS: 151684 kB 单一进程,最多只允许 malloc() 66G 虚拟内存, 超过就会 malloc 失败。 echo 1 > /proc/sys/vm/overcommit_memory 再试试看。 |
16
ryd994 2016-10-09 14:20:47 +08:00 via Android
@xiaozhaoz 楼主说的 vsz 和你说的虚拟内存根本不是一个东西, windows 下的虚拟内存, Linux 下叫 swap
@algas 我又查了一下,你这应就是 bug 导致的访问错误 如果 oom 的话, kernal log 里会有记录,比如: http://askubuntu.com/questions/399458/out-of-memory-when-booting-ubuntu-or-any-linux-distro-from-live-usb |
17
alqaz 2016-10-09 14:29:40 +08:00
是不是应该还是程序有 bug, 既然跑大一点计算才出问题,可不可能是只有这种情况下某些代码才会执行,然后触发了某个 bug?
|
18
xiaozhaoz 2016-10-09 14:35:27 +08:00 1
@ryd994
如果楼主是 ps 命令看到的 VSZ , 那就是虚拟内存。 VSZ virtual memory size of the process in KiB (1024-byte units). Device mappings are currently excluded 楼主确实没说清楚。 如果整个系统只占用 80G RSS ,一般不会 OOM ,但内存 zone 情况不好说。 所以 dmesg 或者 /var/下面的 log 看一眼才能确定。 |
19
xiaozhaoz 2016-10-09 14:37:10 +08:00
楼主的 overcommit_memory 设置是 0 , 所以该程序的虚拟内存 overcommit limit 是动态计算的, 不是 66G 。
如果 overcommit_memory == 2, 超过 66G 会立即异常。 |
20
xiaozhaoz 2016-10-09 14:40:04 +08:00
@ryd994 通过楼主提供的信息,收到是 signal 11 。 所以初步认为是 overcommit , 而不是 oom , oom 是 signal 9.
|
22
WKPlus 2016-10-09 14:47:51 +08:00
CommitLimit 只有在 overcommit_memory 是 2 的时候才生效啊,现在 overcommit_memory 是 0 , CommitLimit 是多少没关系。
可以 dmesg 看下有没有 OOM ,我觉得还是程序本身有问题的可能性比较大。 |
23
xiaozhaoz 2016-10-09 14:50:45 +08:00
@WKPlus
The Linux kernel supports the following overcommit handling modes 0 - Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. It ensures a seriously wild allocation fails while allowing overcommit to reduce swap usage. root is allowed to allocate slightly more memory in this mode. This is the default. 1 - Always overcommit. Appropriate for some scientific applications. Classic example is code using sparse arrays and just relying on the virtual memory consisting almost entirely of zero pages. 2 - Don't overcommit. The total address space commit for the system is not permitted to exceed swap + a configurable amount (default is 50%) of physical RAM. Depending on the amount you use, in most situations this means a process will not be killed while accessing pages but will receive errors on memory allocation as appropriate. Useful for applications that want to guarantee their memory allocations will be available in the future without having to initialize every page. |
25
xiaozhaoz 2016-10-09 14:59:19 +08:00
@WKPlus ,
overcommit 的意思是是否允许过量使用虚存。 所以 0 是不予许,也就是超过一定的虚存会分配失败,但是一个复杂的算法计算上限。 1 是允许, 也就是虚存可以一直分配下去,知道进程的地址空间,或者 oom 发生。 2 是老模式, 就是 ( 50% * 物理内存) + swap 计算虚存使用上限。 |
26
WKPlus 2016-10-09 15:04:06 +08:00
@xiaozhaoz 那么我说的 “ CommitLimit 只有在 overcommit_memory 是 2 的时候才生效啊,现在 overcommit_memory 是 0 , CommitLimit 是多少没关系” 没错啊。我是问你为啥突然贴那个给我
|
27
stephenyin 2016-10-09 17:40:32 +08:00
你这些线程是会频繁启停么? 查查是不是有分支没有 join 或 detach 这些线程!
|
28
algas OP 抱歉一直在外面忙,不在电脑前面
@ryd994 貌似用 2 两个线程也算不了更大的情况,退出前 1s 左右记录到的结果如下, ps aux | grep -i pid username pid cpu mem vsz rss username 1991 99.9 57.4 105758172 75775140 pts/0 R+ 14:21 6:58 ./a.out 260 0.5 |
29
algas OP @xiaozhaoz
虽然我看不太明白你的意思,大概是说程序自身有问题吧?下面是 dmesg 最后一部分的内容,希望有用。 [10523563.169856] a.out[1948]: segfault at 5b9a92500 ip 00000000004034f3 sp 00002b7021521e60 error 6 in a.out[400000+5000] [10523563.169885] a.out[1947]: segfault at 56530c140 ip 00000000004034f3 sp 00002b7021320e60 error 6 in a.out[400000+5000] [10523563.170921] a.out[1954]: segfault at ffffffffb47b7b80 ip 00000000004034f3 sp 00002b7022127e60 error 7 [10523563.171253] a.out[1951]: segfault at 6b7125040 ip 00000000004034f3 sp 00002b7021b24e60 error 6 [10523563.171259] in a.out[400000+5000] [10523563.171267] in a.out[400000+5000] [10524098.407830] a.out[2857]: segfault at 20e363320 ip 00000000004034f3 sp 00002b84d78a7e60 error 6 [10524098.407838] a.out[2858]: segfault at 27b29cd20 ip 00000000004034f3 sp 00002b84d7aa8e60 error 6 [10524098.407840] in a.out[400000+5000] [10524098.407849] a.out[2862]: segfault at 42ef83520 ip 00000000004034f3 sp 00002b84d82ace60 error 6 [10524098.407856] a.out[2856]: segfault at 1a1429920 ip 00000000004034f3 sp 00002b84d76a6e60 error 6 [10524098.407859] in a.out[400000+5000] [10524098.407859] in a.out[400000+5000] [10524098.407867] a.out[2863]: segfault at 49bebcf20 ip 00000000004034f3 sp 00002b84d84ade60 error 6 in a.out[400000+5000] [10524098.407876] in a.out[400000+5000] |
30
algas OP |
31
algas OP @xiaozhaoz
[10548380.539504] a.out[29535]: segfault at fffffffd08858920 ip 00000000004034f3 sp 00002bab3bb23e60 error 7 in a.out[400000+5000] 这里面的 error 7 是指 signal=7 吗? |
33
xiaozhaoz 2016-10-09 23:08:23 +08:00 via Android
error 6,7 指的是用户空间写物理内存异常。不是 signal x
现在可以肯定,是不是 oom 你这个问题好查,每次异常的 eip 都相同,都是 0x4034f3 ,所以反汇编,根据偏移可以推算到代码,才能确切定位是什么问题。 |
35
ryd994 2016-10-10 01:53:19 +08:00 via Android
@algas 主要是我一般没做过这么大规模的。有 segfault 找 valgrind 是我的习惯反射了。
其次就是, int 是 16 位……… long 是 32 long long 是 64 你这个地方应该用 size_t size_t 的意思是当前环境用于表示地址范围大小,保证不溢出 |
36
ryd994 2016-10-10 01:55:21 +08:00 via Android
correlationMatrix
是做计算物理的前辈么?希望能交个朋友 |
37
alqaz 2016-10-10 09:36:36 +08:00
N*N*8=18G 多,很好奇这是哪方面使用的程序。
|
38
araraloren 2016-10-10 09:53:49 +08:00
@alqaz ~~楼主不是大量计算么,保存中间的计算结果什么的吧,不过一次性申请这么多内存也是醉了。。
|
39
algas OP @ryd994
基本上就是这个问题, linux C int 和 long int 都是 32 位, long long int 是 64 位。 malloc 的参数是 size_t 类型,其实就是 unsigned ,比 int 多一位可用。 所以 malloc 单次申请内存大小受到 size_t 的位数限制,我这里把 size_t 益出了。 如果需要申请连续的一大块内存,可能要研究以下 mmap 函数。 我是学统计物理的,主要对付 toy model ,和真正计算实际问题的那种计算物理不太一样。 |
40
algas OP @alqaz
@araraloren 这个是用来保存矩阵的一个数组,是完全填充的。 类似于计算晶格上的振动模式,如果考虑的系统是 200*200 个原子的正方形区域(很小对不对), 关联矩阵就需要 4e4 * 4e4 个元素,基本溢出 int 类型了。 分块计算的倒是可以避免一次申请这么大的内存,但是程序复杂性估计就要上天了 2333 |
41
ryd994 2016-10-10 12:25:47 +08:00 via Android
|
42
ryd994 2016-10-10 12:49:44 +08:00 via Android
@algas 你这样写
size_t N = 220 * 220; size_t 用于表示内存范围的时候不可能溢出,否则就违背定义了。如果我没有记错,在 64 位系统上是 unsigned long long 你的问题是: int 只有 32767 的上限, 220*220=4e4 明显超了,后面 N * N * sizeof(double) 里 N*N 先计算得中间结果,中间结果 promote 为 size_t 与 double 大小相乘后作为 malloc 的参数。第一步时,因为双方都是 int ,所以没有范围调整,所以这里也超了。 重申: size_t 不是 uint16 ,是 uint64 ,如果 size_t 溢出,则当前平台上根本不可能对该内存空间寻址,换言之根本不存在 size_t 溢出而其他方法能正常分配内存的情况。 |