python / python/cpython

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

未關閉
#122,569 1 則留言 0 個 reaction 已指派 1 人 在 GitHub 檢視

@pablogsal 已經在處理了。

開始於 2025年2月17日。

interpreter-core performance type-bug
主要語言
Python
星號
77.2k
分支
36k
PR 合併指標
PR 指標待擷取

描述

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

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。