1 回答
TA贡献1871条经验 获得超8个赞
好的,我相信我已经想通了。看起来 Go 急切地分配并且差异只是由于 Go 内存分析器采样的方式。
Go 急切地分配通道内存
承诺的文档_make
通道的缓冲区使用指定的缓冲区容量进行初始化。
我查看了makechan的代码,它在make(chan chantype, size)
. 它总是直接调用mallocgc
- 没有懒惰。
查看mallocgc的代码,我们可以确认其中没有惰性mallocgc
(除了文档注释没有提到惰性,直接mallocgc
调用c.alloc
)。
pprof 在堆分配级别采样,而不是在调用函数级别
在环顾四周mallocgc
时,我发现了分析代码。在每次mallocgc
调用中,Go 都会检查是否满足其采样条件。如果是这样,它会调用mProf_Malloc将记录添加到堆配置文件中。我无法确认这是 使用的配置文件pprof
,但该文件中的注释表明它是。
采样条件基于自上次采样以来分配的字节数(它从指数分布中抽取样本,平均而言,在每个runtime.MemProfileRate字节分配后)。
这里的重要部分是每次调用mallocgc
都有一定的抽样概率,而不是每次调用foo
. 这意味着如果对 的调用对foo
进行多次调用mallocgc
,我们预计只会对部分mallocgc
调用进行采样。
把它们放在一起
每次我的函数foo
运行时,它都会急切地为 4 个通道分配内存。在每次内存分配调用中,Go 都有机会记录堆配置文件。平均而言,Go 将每 512kB 记录一次堆配置文件(runtime.MemProfileRate 的默认值)。由于这些通道的总大小为 488kB,平均而言,我们预计每次foo
调用只记录一个分配。我上面分享的配置文件是在服务重启后相对较快的,所以分配字节数的差异是纯统计差异的结果。让服务运行一天后,配置文件稳定下来,显示第 142 行和第 146 行分配的字节数相等。
- 1 回答
- 0 关注
- 60 浏览
添加回答
举报