Golang Go语言中查看内存分配,用 strace 跟踪 mmap 调用的数据和 pmap 看到的内存不一致?
1 ,test 代码见: https://go.dev/play/p/2xa_tqKsjWH
2 ,使用命令 strace -e 'signal=!all' -e '!rt_sigreturn,rt_sigaction,rt_sigprocmask,futex' ./test
得到
execve("./test", ["./test"], 0x7fff95cd9970 /* 21 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x4cba70) = 0
sched_getaffinity(0, 8192, [0, 1, 2, 3, 4, 5, 6, 7]) = 32
openat(AT_FDCWD, "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY) = 3
read(3, "2097152\n", 20) = 8
close(3) = 0
mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b9870f000
mmap(NULL, 131072, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b986ef000
mmap(NULL, 1048576, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b985ef000
mmap(NULL, 8388608, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b97def000
mmap(NULL, 67108864, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b93def000
mmap(NULL, 536870912, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b73def000
mmap(0xc000000000, 67108864, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc000000000
mmap(0xc000000000, 67108864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xc000000000
mmap(NULL, 33554432, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b71def000
mmap(NULL, 2165776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b71bde000
mmap(0x7f0b986ef000, 131072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0b986ef000
mmap(0x7f0b9866f000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0b9866f000
mmap(0x7f0b981f5000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0b981f5000
mmap(0x7f0b95e1f000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0b95e1f000
mmap(0x7f0b83f6f000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0b83f6f000
mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b71ade000
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b71ace000
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0b71abe000
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
sigaltstack({ss_sp=0xc000002000, ss_flags=0, ss_size=32768}, NULL) = 0
gettid() = 3689
clone(child_stack=0xc000050000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc000040090) = 3690
clone(child_stack=0xc000052000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc000040490) = 3691
clone(child_stack=0xc00004c000, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS, tls=0xc000040890) = 3693
write(2, "0xc00003c768", 120xc00003c768) = 12
3 ,使用pmap -p 3689
得到
0000000000400000 380K r-x-- /root/logs/test
000000000045f000 420K r---- /root/logs/test
00000000004c8000 16K rw--- /root/logs/test
00000000004cc000 200K rw--- [ anon ]
000000c000000000 65536K rw--- [ anon ]
00007f0b71a7e000 36292K rw--- [ anon ]
00007f0b73def000 263680K ----- [ anon ]
00007f0b83f6f000 4K rw--- [ anon ]
00007f0b83f70000 293564K ----- [ anon ]
00007f0b95e1f000 4K rw--- [ anon ]
00007f0b95e20000 36692K ----- [ anon ]
00007f0b981f5000 4K rw--- [ anon ]
00007f0b981f6000 4580K ----- [ anon ]
00007f0b9866f000 4K rw--- [ anon ]
00007f0b98670000 508K ----- [ anon ]
00007f0b986ef000 384K rw--- [ anon ]
00007ffdc654c000 132K rw--- [ stack ]
00007ffdc65a0000 12K r---- [ anon ]
00007ffdc65a3000 8K r-x-- [ anon ]
我发现 2 个令人疑惑的地方,希望有大佬能指点:
- 地址 7f0b986ef000 处,mmap 调用明明只申请了 128K 内存,怎么 pmap 命令却显示此处有 384K 内存。
- pmap 显示地址 7f0b71a7e000 处的内存有 36292K ,这个内存地址是如何产生的? starce 跟踪到的 mmap 调用并没有看到这个地址。
Golang Go语言中查看内存分配,用 strace 跟踪 mmap 调用的数据和 pmap 看到的内存不一致?
更多关于Golang Go语言中查看内存分配,用 strace 跟踪 mmap 调用的数据和 pmap 看到的内存不一致?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你没有 -f 跟踪子线程 可以先增加跟踪,看看是不是符合预期。
更多关于Golang Go语言中查看内存分配,用 strace 跟踪 mmap 调用的数据和 pmap 看到的内存不一致?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
kernel 会对进程的 memory mapping 作 merge,比如你先申请 128K 再申请 256K,如果 128K 后的 gap 里有 256K 空间可用,
这两块 vma 会被合并在到一起, 在 process mapping 上就体现为一块 384K 的虚拟地址区域.
在Golang(Go语言)中查看内存分配时,遇到使用 strace
跟踪 mmap
调用的数据和 pmap
看到的内存不一致的情况,通常是由以下几个原因导致的:
-
内存管理差异:Go语言有自己的内存管理机制,包括垃圾回收(GC)和内存池。这些机制可能会在运行时动态调整内存使用,导致直接通过
strace
跟踪mmap
调用时看到的内存分配情况与pmap
显示的结果不一致。 -
系统调用与进程状态:
strace
跟踪的是系统调用,它记录的是mmap
请求的内存大小,而pmap
显示的是进程当前实际使用的内存状态。这两者之间存在时间差和状态差异,可能导致数据不一致。 -
内存碎片和共享内存:Go的内存管理可能导致内存碎片,或者在不同goroutine之间共享内存。这些复杂的内存使用情况可能不会被
strace
准确捕捉,但会在pmap
中有所体现。 -
工具使用限制:
strace
和pmap
在使用时都有其局限性。例如,strace
可能因为系统调用过多而丢失部分信息,而pmap
显示的内存信息可能受到系统内核参数的影响。
为了更准确地分析内存使用情况,建议使用Go语言的内存分析工具,如 pprof
,它可以直接与Go的运行时(runtime)交互,提供更准确和详细的内存分配和使用情况。同时,结合系统监控工具(如 top
、htop
)和日志分析,可以更全面地了解内存的使用状态。