python / python/cpython

GC - long_lived_pending is not decremented when a generation-2 object's ref count goes to 0

Offen
#122,569 1 Kommentar 0 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

@pablogsal arbeitet bereits daran.

Seit 17.2.2025.

interpreter-core performance type-bug
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Bug report

Bug description:

Given the idea and documentation around the long_lived_pending / long_lived_total > 0.25 check, I would expect long_lived_pending to be the total number of objects that (1) have survived a generation-1 collection, and (2) are still live (i.e., ref count has not been decremented to 0).

From the behavior I'm seeing, I think only (1) is true. The example code below is contrived to promote many objects into generation-2 and then cause them to be deleted by their ref counts being decremented to 0. Hence there is no reason for Python to perform a generation-2 collection. Nevertheless, it does so repeatedly, collecting nothing each time. This seems sub-optimal, since these collections are expensive and are not doing anything.

import gc
import time
from typing import Any

class Temp:
  pass

accumulating_list = []

def gc_callback(phase: str, info: dict[str, Any]) -> None:
  generation = info['generation']
  if generation == 2:
    print(phase, info, len(gc.get_objects(2)))
  if phase == "stop" and generation == 1:
    # The GC that just ended will have promoted most of the Temps in
    # accumulating_list into generation-2. Drop references to to them here,
    # causing them to be immediately deleted.
    accumulating_list.clear()

gc.callbacks.append(gc_callback)
gc.set_threshold(10, 2, 2)

for x in range(100000):
  accumulating_list.append(Temp())
  time.sleep(0.001)

Is it working as intended that long_lived_pending is not decremented when a corresponding object is deleted by its ref count dropping to 0? This would avoid generation-2 collections except where actually useful. It feels to me like this should happen, although perhaps it's infeasible or too expensive?

Note: Although this is a contrived example, we are seeing this in a real world largeish Python program. It's exacerbated by the default GC thresholds being set really low, which results in even short-lived objects (measured by time) being promoted quickly into generation-2.

CPython versions tested on:

3.11

Operating systems tested on:

macOS

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.