In the process of learning the memory management part of the Go language, I found a very interesting problem. Today, I use this article:
- 1. Throwing this question to everyone, I suggest that after seeing this question, you can think about it for yourself 🤔 and then read the following.
- 2. Further strengthen your understanding of the Go memory architecture
Before starting this article, let's quickly review the core knowledge points related to the "Go memory architecture" and learn from the past .
A quick review of "TCMalloc memory management architecture"
Let's briefly review the "TCMalloc memory management architecture". For a detailed explanation, you can view the previous article "18 Graphs to Decrypt the New Era Memory Allocator TCMalloc"
Pain points
Multi-threading era --->
Thread shared memory --->
Thread application for memory will cause competition --->
Competition lock --->
lock affects performance.
solution
Increase the memory cache on each thread.
The simple architecture diagram is as follows:
A quick review of "Go Memory Management Architecture"
Then briefly review the "Go Memory Management Architecture". For a detailed explanation, you can view the previous article "Analysis of Go Memory Management Architecture"
Pain points
Ditto.
solution
Same as above, based on "TCMalloc" implementation.
The simple architecture diagram is as follows:
interesting question
Regarding this interesting question, careful friends may have discovered it, and the question is as follows:
Why is the thread cache of Go's memory managermcache
p
, but not by the real system threadm
?
personal thinking time
Isn't it interesting, on this subject. On the opposite side, you might as well stop and think for a few minutes:
Why?
decrypt
According to the original design idea of TCMalloc
, the thread cache mcache
should indeed be bound to the system thread M
.
Then we assume: According to the original idea of TCMalloc
mcache
, bind ---e2c06fa212d50618ab0044d35ac4bc1f--- to the system thread M
. Then we just need to see what's wrong with this assumption .
To demonstrate this assumption, we need to take a brief look at "Go's scheduling model GMP
".
Go's scheduling model GMP
Go directly to the entry-level "Scheduling model of Go GMP
" architecture diagram:
Regarding the principle of "Go's scheduling model GMP
", you should read countless articles, I will not go into details here, if you are not familiar with it, you can search by yourself.
Here is a brief introduction to the entry-level knowledge about GMP
. In fact, GMP
corresponds only to the logical structure of the Go language itself. The meaning is as follows:
-
M
:代表结构体m
,Machine
b7f286dbe435fac47f5033f4942493f9--- ,这个结构体的核心是会和真正的系统线程thread
。 -
G
:代表结构体g
,Goroutine
51b4c0bf4b0de92ba2c3077733e3003b--- ,这个结构体就是大家协程
,简单理解其实就是这个结构体Binds a function that needs to be executed concurrently. -
P
:代表结构体p
,Processor
e1818d41349c7be8c301d690031ac6f8--- ,这个结构体表示逻辑处理器
,通过这个结构体和计算机的逻辑处理器To establish a corresponding relationship, the number ofP
is usually consistent with the number of logical processors of the computer through theruntime.GOMAXPROCS(runtime.NumCPU())
setting.
Simple responsibilities and relationships of the three:
P
- and one
M
bind each other - Maintained a queue of executable
G
- and one
M
- and one
P
bind each other - 负责
G
e5ffdaecee01fa9fc67f19796db4e452---的调度,通过调度当前M
P
的G
队列、G
Queue, to achieveG
can be executed concurrently. - Responsible for executing
P
the current scheduledG
- and one
此阶段结论:以上P
的数量M
的数量是一一对应的,所以把mcache
系统线程M
P
looks all right. So our assumption above " according to the original idea of --- 7d5d68e34d4b219bcddece85a9e73e9d TCMalloc
, put mcache
binding system thread M
up " does not seem to be a problem at present.
We continue to look down, a special scenario M
will be unbound with P
.
System calls for I/O operations
When G
executes a system call of an I/O operation, such as read
, write
, because the system call is blocked in the process of The blocking caused by the process of copying data is not in the scope of this article, and the following articles will explain in detail) the problem, and the following operations will occur:
- 当前
G
(我们g1
)的M
(我们命名为m1
)和当前的P
(We named itp1
)Unbind - The above
p1
will bind an otherM
(m2
) -
m1
After the system call is executed, it will be placed idleM
in the linked list
Since m1
will be put into the idle list, does this mean that the m1
on mcache
cannot currently be reused, so it seems right? mcache
p1
.
Conclusion: Since M
may be blocked by a system call that performs an I/O operation (reason: the process of copying data from the kernel to user mode is blocked), M
P
be the same as the current- P
解绑,当前P
新的M
,之前的M
M
Linked list. The previous M
mcache
will not be effectively reused, but mcache
is bound to P
. This problem does not exist , so mcache
P
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。