@@ -351,6 +351,7 @@ follows these steps in order:
351
351
the reference counts fall to 0, triggering the destruction of all unreachable
352
352
objects.
353
353
354
+
354
355
Optimization: incremental collection
355
356
====================================
356
357
@@ -484,6 +485,46 @@ specifically in a generation by calling `gc.collect(generation=NUM)`.
484
485
```
485
486
486
487
488
+ Optimization: visiting reachable objects
489
+ ========================================
490
+
491
+ An object cannot be garbage if it can be reached.
492
+
493
+ To avoid having to identify reference cycles across the whole heap, we can
494
+ reduce the amount of work done considerably by first moving most reachable objects
495
+ to the ` visited ` space. Empirically, most reachable objects can be reached from a
496
+ small set of global objects and local variables.
497
+ This step does much less work per object, so reduces the time spent
498
+ performing garbage collection by at least half.
499
+
500
+ > [ !NOTE]
501
+ > Objects that are not determined to be reachable by this pass are not necessarily
502
+ > unreachable. We still need to perform the main algorithm to determine which objects
503
+ > are actually unreachable.
504
+
505
+ We use the same technique of forming a transitive closure as the incremental
506
+ collector does to find reachable objects, seeding the list with some global
507
+ objects and the currently executing frames.
508
+
509
+ This phase moves objects to the ` visited ` space, as follows:
510
+
511
+ 1 . All objects directly referred to by any builtin class, the ` sys ` module, the ` builtins `
512
+ module and all objects directly referred to from stack frames are added to a working
513
+ set of reachable objects.
514
+ 2 . Until this working set is empty:
515
+ 1 . Pop an object from the set and move it to the ` visited ` space
516
+ 2 . For each object directly reachable from that object:
517
+ * If it is not already in ` visited ` space and it is a GC object,
518
+ add it to the working set
519
+
520
+
521
+ Before each increment of collection is performed, the stacks are scanned
522
+ to check for any new stack frames that have been created since the last
523
+ increment. All objects directly referred to from those stack frames are
524
+ added to the working set.
525
+ Then the above algorithm is repeated, starting from step 2.
526
+
527
+
487
528
Optimization: reusing fields to save memory
488
529
===========================================
489
530
@@ -532,8 +573,8 @@ of `PyGC_Head` discussed in the `Memory layout and object structure`_ section:
532
573
currently in. Instead, when that's needed, ad hoc tricks (like the
533
574
` NEXT_MASK_UNREACHABLE ` flag) are employed.
534
575
535
- Optimization: delay tracking containers
536
- =======================================
576
+ Optimization: delayed untracking of containers
577
+ ==============================================
537
578
538
579
Certain types of containers cannot participate in a reference cycle, and so do
539
580
not need to be tracked by the garbage collector. Untracking these objects
@@ -548,8 +589,8 @@ a container:
548
589
As a general rule, instances of atomic types aren't tracked and instances of
549
590
non-atomic types (containers, user-defined objects...) are. However, some
550
591
type-specific optimizations can be present in order to suppress the garbage
551
- collector footprint of simple instances. Some examples of native types that
552
- benefit from delayed tracking :
592
+ collector footprint of simple instances. Historically, both dictionaries and
593
+ tuples were untracked during garbage collection. Now it is only tuples :
553
594
554
595
- Tuples containing only immutable objects (integers, strings etc,
555
596
and recursively, tuples of immutable objects) do not need to be tracked. The
@@ -558,14 +599,8 @@ benefit from delayed tracking:
558
599
tuples at creation time. Instead, all tuples except the empty tuple are tracked
559
600
when created. During garbage collection it is determined whether any surviving
560
601
tuples can be untracked. A tuple can be untracked if all of its contents are
561
- already not tracked. Tuples are examined for untracking in all garbage collection
562
- cycles. It may take more than one cycle to untrack a tuple.
563
-
564
- - Dictionaries containing only immutable objects also do not need to be tracked.
565
- Dictionaries are untracked when created. If a tracked item is inserted into a
566
- dictionary (either as a key or value), the dictionary becomes tracked. During a
567
- full garbage collection (all generations), the collector will untrack any dictionaries
568
- whose contents are not tracked.
602
+ already not tracked. Tuples are examined for untracking when moved from the
603
+ young to the old generation.
569
604
570
605
The garbage collector module provides the Python function ` is_tracked(obj) ` , which returns
571
606
the current tracking status of the object. Subsequent garbage collections may change the
@@ -578,11 +613,9 @@ tracking status of the object.
578
613
False
579
614
>>> gc.is_tracked([])
580
615
True
581
- >>> gc.is_tracked({} )
616
+ >>> gc.is_tracked(("a", 1) )
582
617
False
583
618
>>> gc.is_tracked({"a": 1})
584
- False
585
- >>> gc.is_tracked({"a": []})
586
619
True
587
620
```
588
621
0 commit comments