-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
GH-126491: Lower heap size limit with faster marking #127519
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
Changes from 23 commits
3038a78
c024484
e8497ae
4c1a6bc
6efb4c0
b1c7ab0
07f228b
51ff78e
df907b5
9ca64f5
bda13f4
d9d63c8
57b8820
a607059
1545508
a1a38c8
68fc90b
8893cf5
ba20c7c
8262bf0
3c2116e
72d0284
0f182e2
d3c21bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -199,22 +199,22 @@ unreachable: | |||||||||
|
|
||||||||||
| ```pycon | ||||||||||
| >>> import gc | ||||||||||
| >>> | ||||||||||
| >>> | ||||||||||
| >>> class Link: | ||||||||||
| ... def __init__(self, next_link=None): | ||||||||||
| ... self.next_link = next_link | ||||||||||
| ... | ||||||||||
| ... | ||||||||||
| >>> link_3 = Link() | ||||||||||
| >>> link_2 = Link(link_3) | ||||||||||
| >>> link_1 = Link(link_2) | ||||||||||
| >>> link_3.next_link = link_1 | ||||||||||
| >>> A = link_1 | ||||||||||
| >>> del link_1, link_2, link_3 | ||||||||||
| >>> | ||||||||||
| >>> | ||||||||||
| >>> link_4 = Link() | ||||||||||
| >>> link_4.next_link = link_4 | ||||||||||
| >>> del link_4 | ||||||||||
| >>> | ||||||||||
| >>> | ||||||||||
| >>> # Collect the unreachable Link object (and its .__dict__ dict). | ||||||||||
| >>> gc.collect() | ||||||||||
| 2 | ||||||||||
|
|
@@ -459,11 +459,11 @@ specifically in a generation by calling `gc.collect(generation=NUM)`. | |||||||||
| >>> # Create a reference cycle. | ||||||||||
| >>> x = MyObj() | ||||||||||
| >>> x.self = x | ||||||||||
| >>> | ||||||||||
| >>> | ||||||||||
| >>> # Initially the object is in the young generation. | ||||||||||
| >>> gc.get_objects(generation=0) | ||||||||||
| [..., <__main__.MyObj object at 0x7fbcc12a3400>, ...] | ||||||||||
| >>> | ||||||||||
| >>> | ||||||||||
| >>> # After a collection of the youngest generation the object | ||||||||||
| >>> # moves to the old generation. | ||||||||||
| >>> gc.collect(generation=0) | ||||||||||
|
|
@@ -515,6 +515,44 @@ increment. All objects directly referred to from those stack frames are | |||||||||
| added to the working set. | ||||||||||
| Then the above algorithm is repeated, starting from step 2. | ||||||||||
|
|
||||||||||
| Determining how much work to do | ||||||||||
| ------------------------------- | ||||||||||
|
|
||||||||||
| We need to do a certain amount of work to enusre that garbage is collected, | ||||||||||
| but doing too much work slows down execution. | ||||||||||
|
|
||||||||||
| To work out how much work we need to do, consider a heap with `L` live objects | ||||||||||
| and `G0` garbage objects at the start of a full scavenge and `G1` garbage objects | ||||||||||
| at the end of the scavenge. We don't want amount of garbage to grow, `G1 ≤ G0`, and | ||||||||||
| we don't want too much garbage (say 1/3 of the heap maximum), `G0 ≤ L/2`. | ||||||||||
| For each full scavenge we must visit all objects, `T == L + G0 + G1`, during which | ||||||||||
| `G1` garbage objects are created. | ||||||||||
|
|
||||||||||
| The number of new objects created `N` must be at least the new garbage created, `N ≥ G1`, | ||||||||||
| assuming that the number of live objects remains roughly constant. | ||||||||||
| If we set `T == 4*N` we get `T > 4*G1` and `T = L + G0 + G1` => `L + G0 > 3G1` | ||||||||||
| For a steady state heap `G0 == G1` we get `L > 2G` and the desired garbage ratio. | ||||||||||
|
||||||||||
| For a steady state heap `G0 == G1` we get `L > 2G` and the desired garbage ratio. | |
| For a steady state heap `G0 == G1` we get `L > 2*G0` and the desired garbage ratio. |
Outdated
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 a steady state heap `G0 == G1` we get `L > 2G` and the desired garbage ratio. | |
| For a steady state heap (`G0 == G1`) we get `L > 2G` and the desired garbage ratio. |
Outdated
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.
| Since `I ≥ G0 + G1` (not strictly true, but close enough) | |
| Since `I ≈ G0 + G1` (not strictly true, but close enough) |
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.
The increments (I) can include some of the live heap, depending on the how much is keep alive by C extensions.
So ≥ is more correct. Although ≳ is even more correct.
Outdated
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.
| `T == M + I == (6N + I)/2` and `(6N + I)/2 ≥ 4G`, so we can keep up. | |
| `T == M + I == (6N + I)/2` and `(6N + I)/2 ≳ 4G`, so we can keep up. |
Outdated
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.
| than `I` Suppose `M == 10I`, then `T ≅ 3N`. | |
| than `I`. If `M == 10I`, then `T ≅ 3N`. |
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.