-
Notifications
You must be signed in to change notification settings - Fork 5.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
*: Support to trigger GC when memory usage is large. #38179
Conversation
[REVIEW NOTIFICATION] This pull request has been approved by:
To complete the pull request process, please ask the reviewers in the list to review by filling The full list of commands accepted by this bot can be found here. Reviewer can indicate their review by submitting an approval review. |
e67bc76
to
77870f3
Compare
util/gctuner/memory_limit_tuner.go
Outdated
// So we can change memory limit dynamically to avoid frequent GC when memory usage is greater than the soft limit. | ||
type memoryLimitTuner struct { | ||
finalizer *finalizer | ||
isTuning atomic.Bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use atomicutil.Bool?
util/gctuner/memory_limit_tuner.go
Outdated
debug.SetMemoryLimit(softLimit) | ||
} | ||
|
||
func (t *memoryLimitTuner) calcSoftMemoryLimit() int64 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func (t *memoryLimitTuner) calcSoftMemoryLimit() int64 { | |
func (t *memoryLimitTuner) calcMemoryLimit() int64 { |
util/gctuner/memory_limit_tuner.go
Outdated
ratio := float64(100+gogc) / 100 | ||
// If theoretical NextGC(Equivalent to HeapInUse * (100 + GOGC) / 100) is bigger than MemoryLimit twice in a row, | ||
// the second GC is caused by MemoryLimit. | ||
if r.HeapInuse > uint64(float64(debug.SetMemoryLimit(-1))/ratio) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is r.HeapInuse * ratio
more readable according to the comment above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to explain why "twice". It really hard to understand
|
||
memory210mb := allocator.alloc(210 << 20) | ||
require.True(t, gcNum < getNowGCNum()) | ||
// Test waiting for reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to check whether waitingReset
is true here?
|
||
allocator.free(memory210mb) | ||
allocator.free(memory100mb) | ||
// Can GC in 80% again |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does Can GC
mean?
gcNum = getNowGCNum() | ||
memory210mb = allocator.alloc(210 << 20) | ||
time.Sleep(100 * time.Millisecond) | ||
require.True(t, gcNum < getNowGCNum()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this GC trigger by memory_limit?
require.True(t, gcNum < getNowGCNum()) | ||
allocator.free(memory210mb) | ||
allocator.free(memory600mb) | ||
time.Sleep(1 * time.Second) // If test.count > 1, wait tuning finished. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check isTunning
, waitingReset
and times
after this Sleep?
util/gctuner/memory_limit_tuner.go
Outdated
if t.times >= 2 && t.waitingReset.CompareAndSwap(false, true) { | ||
t.times = 0 | ||
go func() { | ||
debug.SetMemoryLimit(math.MaxInt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MaxInt or MaxInt64?
util/gctuner/memory_limit_tuner.go
Outdated
// If theoretical NextGC(Equivalent to HeapInUse * (100 + GOGC) / 100) is bigger than MemoryLimit twice in a row, | ||
// the second GC is caused by MemoryLimit. | ||
// All GC is divided into the following three cases: | ||
// 1. In normal, HeapInUse * (100 + GOGC) / 100 < MemoryLimit, NextGC = HeapInUse * (100 + GOGC) / 100. | ||
// 2. The first time HeapInUse * (100 + GOGC) / 100 >= MemoryLimit, NextGC = MemoryLimit. But this GC is trigger by GOGC. | ||
// 3. The second time HeapInUse * (100 + GOGC) / 100 >= MemoryLimit. This GC is trigger by MemoryLimit. | ||
// We set MemoryLimit to MaxInt, so the NextGC will be HeapInUse * (100 + GOGC) / 100 again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// If theoretical NextGC(Equivalent to HeapInUse * (100 + GOGC) / 100) is bigger than MemoryLimit twice in a row, | |
// the second GC is caused by MemoryLimit. | |
// All GC is divided into the following three cases: | |
// 1. In normal, HeapInUse * (100 + GOGC) / 100 < MemoryLimit, NextGC = HeapInUse * (100 + GOGC) / 100. | |
// 2. The first time HeapInUse * (100 + GOGC) / 100 >= MemoryLimit, NextGC = MemoryLimit. But this GC is trigger by GOGC. | |
// 3. The second time HeapInUse * (100 + GOGC) / 100 >= MemoryLimit. This GC is trigger by MemoryLimit. | |
// We set MemoryLimit to MaxInt, so the NextGC will be HeapInUse * (100 + GOGC) / 100 again. | |
This `if` checks whether the **last** GC was triggered by MemoryLimit as far as possible. | |
If the **last** GC was triggered by MemoryLimit, we'll set MemoryLimit to MAXVALUE to return control back to GOGC to avoid frequent GC when memory usage fluctuates above and below MemoryLimit. | |
The logic we judge whether the **last** GC was triggered by MemoryLimit is as follows: | |
suppose `NextGC` = `HeapInUse * (100 + GOGC) / 100)`, | |
- If NextGC < MemoryLimit, the **next** GC will **not** be triggered by MemoryLimit thus we do not care about why the **last** GC is triggered. And MemoryLimit will not be reset this time. | |
- Only if NextGC >= MemoryLimit , the **next** GC will be triggered by MemoryLimit. Thus we need to reset MemoryLimit after the next GC happens if needed. |
util/gctuner/memory_limit_tuner.go
Outdated
memoryLimit := t.calcMemoryLimit() | ||
if EnableGOGCTuner.Load() { | ||
memoryLimit = math.MaxInt64 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memoryLimit := t.calcMemoryLimit() | |
if EnableGOGCTuner.Load() { | |
memoryLimit = math.MaxInt64 | |
} | |
memoryLimit := math.MaxInt64 | |
if !EnableGOGCTuner.Load() { | |
memoryLimit = t.calcMemoryLimit() | |
} |
debug.SetMemoryLimit(math.MaxInt) | ||
resetInterval := 1 * time.Minute // Wait 1 minute and set back, to avoid frequent GC | ||
failpoint.Inject("testMemoryLimitTuner", func(val failpoint.Value) { | ||
if val, ok := val.(bool); val && ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why check ok ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For linter, type assertion must be checked (forcetypeassert)
/merge |
This pull request has been accepted and is ready to merge. Commit hash: 0c39f03
|
TiDB MergeCI notify🔴 Bad News! New failing [1] after this pr merged.
|
What problem does this PR solve?
Issue Number: ref #37816
Problem Summary:
What is changed and how it works?
Add the system variable
tidb_server_memory_limit_gc_trigger
and support to trigger GC when memory usgae is larger thantidb_server_memory_limit_gc_trigger
*tidb_server_memory_limit
.Check List
Tests
Side effects
Documentation
Release note
Please refer to Release Notes Language Style Guide to write a quality release note.