Skip to content

builtin: add closure lifetime reclamation#27483

Open
GGRei wants to merge 5 commits into
vlang:masterfrom
GGRei:fix/27445-closure-context-leak-minimal
Open

builtin: add closure lifetime reclamation#27483
GGRei wants to merge 5 commits into
vlang:masterfrom
GGRei:fix/27445-closure-context-leak-minimal

Conversation

@GGRei

@GGRei GGRei commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a recovery of the closure leak work discussed in #27446.

It fixes #27445 by adding the compiler/runtime foundation for captured closure reclamation. Captured closure contexts now use collectable memdup instead of memdup_uncollectable, while the closure runtime keeps live contexts reachable through a scanned table.

Non-escaping local captured closures are cleaned up when their scope is left, including normal scope exit, return, and labeled/non-labeled break / continue.

The cleanup remains conservative. Closures are not destroyed when they escape through return values, copies, function arguments, struct fields, globals, defer blocks, spawn, or go.

This PR also adds an explicit, reusable closure lifetime/reclaim API that frame-based or immediate-mode systems can use without exposing raw closure destruction.

Public API added:

  • closure.new_lifetime()
  • Lifetime.frame(work fn ()) !
  • Lifetime.reclaim(retain int) !
  • Lifetime.reclaim_all() !
  • Lifetime.dispose() !
  • Lifetime.suspend(work fn ()) !
  • Lifetime.untracked(work fn ()) !

The API lets a caller create a lifetime owner, run one transient frame under that owner, reclaim old frame-owned closure contexts, and explicitly keep persistent callbacks outside reclaim when needed.

Important contract: frame, suspend, and untracked borrow their work callback. The lifetime owns only the closure contexts created while a frame is active.

Changes

  • Add explicit closure context ownership through closure_create_with_data.
  • Keep live closure contexts rooted under Boehm while the closure is alive.
  • Clear root table entries before deleting them.
  • Generate collectable closure contexts for captured anonymous functions.
  • Distinguish owned value receivers from borrowed pointer receivers for method-value closures.
  • Add conservative local non-escaping closure cleanup in Cgen.
  • Add a reusable closure lifetime/reclaim API.
  • Add regression coverage for the memory growth pattern, generated-C safety cases, skip-unused, and lifetime API behavior.
  • Keep escaping GUI-style handlers alive unless an explicit owner/lifetime policy releases them.

Follow-up

This PR prepares the ground for vlang/gui#58, but does not claim to fully fix it by itself.

The remaining work should be done in vlang/gui by using the new lifetime API when replacing frame/layout trees in Window.update().

Tests

All tests below were run on the current PR head 3d974672d.

./v_pr19_verify fmt -verify \
  vlib/builtin/closure/closure.c.v \
  vlib/builtin/closure/closure_nix.c.v \
  vlib/builtin/closure/closure_windows.c.v \
  vlib/v/gen/c/cgen.v \
  vlib/v/gen/c/fn.v \
  vlib/v/gen/c/for.v \
  vlib/v/gen/c/closure_context_codegen_test.v \
  vlib/v/tests/fns/closure_context_boehm_root_test.c.v \
  vlib/v/tests/fns/closure_context_skip_unused_test.v \
  vlib/v/tests/fns/closure_lifetime_api_test.v \
  vlib/v/tests/loops/for_c_init_closure_cleanup_test.v

./v_pr19_verify missdoc --verify vlib/builtin/closure/closure.c.v

./v_pr19_verify test vlib/v/gen/c/closure_context_codegen_test.v
./v_pr19_verify test vlib/v/tests/fns/closure_lifetime_api_test.v
./v_pr19_verify -gc none test vlib/v/tests/fns/closure_lifetime_api_test.v
./v_pr19_verify -gc boehm test vlib/v/tests/fns/closure_lifetime_api_test.v
./v_pr19_verify -gc boehm_leak test vlib/v/tests/fns/closure_lifetime_api_test.v
./v_pr19_verify -cstrict test vlib/v/tests/fns/closure_lifetime_api_test.v

./v_pr19_verify test vlib/v/tests/fns/closure_context_skip_unused_test.v
./v_pr19_verify -gc boehm_leak test vlib/v/tests/fns/closure_context_skip_unused_test.v

./v_pr19_verify -gc boehm test vlib/v/tests/fns/closure_context_boehm_root_test.c.v
./v_pr19_verify -gc none test vlib/v/tests/fns/closure_context_boehm_root_test.c.v

./v_pr19_verify -gc none test vlib/v/tests/loops/for_c_init_closure_cleanup_test.v
./v_pr19_verify test vlib/v/tests/defer/scoped_defer_test.v
./v_pr19_verify test vlib/v/gen/c/coutput_test.v

VJOBS=1 ./v_pr19_verify test vlib/v/tests/fns
git diff --check

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.

@GGRei GGRei changed the title builtin: reclaim captured closure contexts builtin: add closure lifetime reclamation Jun 18, 2026
@medvednikov

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d974672df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
@GGRei

GGRei commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c3bdbd8f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread vlib/v/gen/c/cgen.v Outdated
Comment thread vlib/v/gen/c/for.v
Comment thread vlib/v/gen/c/cgen.v Outdated
@GGRei

GGRei commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: cd22d8723d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@GGRei

GGRei commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

Ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Capturing closures leak their captured context under -gc boehm (unbounded growth in frame-based apps)

2 participants