1159. Lesson identity
1160. Learning objective
After this lesson, you can model the lifecycle of one game resource, identify its owner or borrower, correct missing cleanup transitions, distinguish reuse from recovery, and explain how the design prevents double release.
1161. Why this matters
A resource can be created correctly and still cause failures if it remains active after its valid use ends or is released while another system still depends on it. Textures, audio handles, subscriptions, file-like objects, pooled entities, and GPU-facing resources all need explicit lifecycle contracts.
Repeated scene changes, cancellation, retries, and partial initialization can expose stale references, duplicated callbacks, leaked claims, or premature release. AI may suggest cleanup code, but it cannot infer an undocumented ownership contract safely. You must determine who controls each claim, when use ends, and what happens on every terminal path.
1162. Prior knowledge
You should be able to distinguish a measured performance observation from a hypothesis, as practiced in 3.7 L2 — Measure before changing. You should also be able to trace a small code path and identify the object or system requesting a resource. No particular language or engine API is required.
1163. Core concept
A resource lifecycle is a sequence of responsibilities, not merely a constructor followed by a destructor.
A useful lifecycle distinguishes these operations:
- Create or acquire: allocate a resource, open it, subscribe, or obtain a claim from another owner.
- Use: perform work while the resource or claim remains valid.
- Dispose: announce that a component has finished and execute that component's cleanup contract.
- Release: close, unsubscribe, decrement a claim, return an item to a pool, or otherwise relinquish what was acquired. In some APIs,
disposeperforms release; in others, it coordinates several release operations. - Reuse: begin a new valid use period for an existing resource or pooled equivalent.
- Recover: respond to failed creation, failed use, partial initialization, or failed cleanup by retrying, selecting a fallback, or recording and reporting the failure.
Every acquisition needs an explicit ownership contract, but that does not mean every user releases the underlying shared resource. An owner releases the claims it owns. A borrower ends its use and returns or relinquishes its borrowed claim according to the contract; it must not destroy or release an underlying resource owned by a pool, manager, or shared service.
1164. Owner–lifetime–exit model
| Question | Required answer |
|---|---|
| Owner or borrower | Which object or system owns the resource, and which components only borrow it? |
| Lifetime | During which states or operations may each claim be used? |
| Exit | Which event ends a claim, and what cleanup, return, release, or handoff follows? |
| Lifecycle state | Responsibility | Evidence to inspect |
|---|---|---|
| Created or acquired | Record the resource or claim and its responsible owner | Allocation, subscription, open, or pool-checkout result |
| In use | Keep the claim valid and prevent release during use | Calls that consume or reference it |
| Disposing | Stop new use and execute cleanup at most once | Guard, state change, or lifecycle callback |
| Released or returned | Relinquish only the claims that this component owns | Close, unsubscribe, decrement, return-to-pool, or release call |
| Reused | Establish a new valid claim and user | Pool checkout or reacquisition transition |
| Recovering | Handle failure without pretending acquisition succeeded | Retry, fallback, rollback, logging, or failure notification |
Represent the lifecycle with arrows, a numbered transition list, or a state-transition table. Label every transition with its triggering event. If the owner, borrower, event, or next state is unknown, mark it as a defect instead of assuming API behavior.
1165. Concrete example
Consider a DialogueAudioSession that asks an audio pool for a stream and then subscribes to a dialogue-completion callback.
Dialogue starts
-> Request stream from pool
-> If checkout succeeds, subscribe to completion callback
-> Play dialogue
-> Dialogue ends, is skipped, or its scene unloads
-> Dispose session once
-> Unsubscribe callback and return stream claim to pool
-> Pool may later issue the stream under a new claim
The pool may own the underlying stream while the session owns only the checkout claim. In that contract, the session must return its claim but must not destroy the pool's underlying resource.
Inspect at least these paths:
- Normal completion: the final line ends, session cleanup runs once, the callback is removed, and the stream claim returns to the pool.
- Cancellation or unload: the same cleanup obligations apply even though the final line never runs.
- Failed acquisition: no stream claim exists, so cleanup must not return or release one. The session follows a defined reporting or recovery path.
- Partial acquisition: the stream checkout succeeds but callback subscription fails. Cleanup must return the acquired stream claim while avoiding an unsubscribe operation for a subscription that was never established.
1166. Reuse is not recovery
Reuse and recovery can both lead to a usable state, but they answer different questions:
- Reuse: How does a valid existing resource receive a new owner or borrower claim after a previous claim ends?
- Recovery: What response follows a failure or partial state?
Returning a stream to a pool and checking it out later is reuse. Recording a checkout failure, rolling back a partially created session, retrying under a stated policy, or selecting a fallback is recovery.
1167. Preventing double release
Cleanup may be requested by more than one event. For example, cancellation and scene unload could occur close together. A safe lifecycle must make cleanup idempotent or guard it so the owned claim is relinquished at most once.
A conceptual guard can be expressed as:
if state is Active or PartiallyAcquired:
change state to Disposing
release only claims recorded as acquired
clear those claim records
change state to Disposed
else:
perform no second release
The exact syntax is API-dependent. The important evidence is the state transition or guard that prevents two terminal events from releasing the same claim twice.
1168. Ownership checklist
For each resource or claim, answer:
- Who owns the underlying resource?
- Does this component own it, share it, or borrow it?
- Which successful acquisition records that responsibility?
- Which events end valid use?
- Which owned claims must be released, returned, closed, or unsubscribed?
- Which underlying resources must this borrower leave intact?
- How does cleanup know whether acquisition was full, partial, or unsuccessful?
- What prevents cleanup from releasing the same claim twice?
- What transition enables reuse?
- What response constitutes recovery after failure?
1169. Assessed practical checkpoint
Complete Resource lifecycle correction checkpoint. You will inspect a deliberately incomplete lifecycle for a pooled dialogue-audio stream and callback subscription.
The supplied lifecycle includes normal completion, cancellation, and partial-acquisition paths but omits several ownership and cleanup decisions. Identify the underlying owner and borrowed claims, mark or label missing transitions, distinguish reuse from recovery, and explain the guard against double release.
You may submit any one of these equivalent formats:
- an annotated diagram;
- a structured text transition list; or
- a state-transition table with columns for state, owner or borrower, triggering event, action, next state, and failure path.
Visual circling is not required. Mark defects with labels such as MISSING OWNER, MISSING TRANSITION, DOUBLE-RELEASE RISK, or INVALID RELEASE.
1170. Validation and evidence
The practical checkpoint is evaluated using these criteria:
- one named owner for the underlying resource and a clear statement of what the session owns or borrows;
- create or acquire, use, dispose, and release or return transitions;
- normal completion, cancellation, and partial-acquisition paths;
- a failed-acquisition path that does not release an unacquired claim;
- a correct distinction between reuse and recovery;
- an explicit state change or guard against double release;
- no use after release or return.
A lifecycle is complete when another developer can determine who cleans up, when cleanup begins, which claims are relinquished, whether cleanup is safe to repeat, and what happens after failure. Unknown behavior must remain marked as a defect rather than being filled with an invented API assumption.
1171. Key takeaways
- Resource lifetime is defined by ownership, borrowing, valid-use states, and exit events.
disposecoordinates a component's cleanup contract; it is not automatically identical to releasing an underlying shared resource.- Owners release their owned claims. Borrowers end use without destroying resources owned elsewhere.
- Normal completion, cancellation, failed acquisition, and partial acquisition need explicit paths.
- Reuse creates a new valid claim; recovery responds to failure.
- A lifecycle needs an observable guard or state transition that prevents double release.
1172. Next lesson
Continue to 3.8 L2 — Reproduce a lifecycle failure / Reproducir un fallo del ciclo de vida. Use the corrected lifecycle and ownership note as inputs for a bounded failure reproduction.
1173. Knowledge check
Answer these items for yourself before reading the answers.
A session borrows a stream from a pool. Which cleanup contract is correct?
Show answer and feedback
Answer: The session ends use and returns its claim; the pool retains responsibility for the underlying resource.
Why: A borrower must end use according to the contract without destroying an underlying resource owned by the pool.
A stream checkout succeeds, but callback subscription fails. Which actions belong in the partial-acquisition path?
Show answer and feedback
Answer: Return the acquired stream claim.; Record or report the subscription failure.
Why: Partial cleanup releases only claims that were successfully acquired and follows a defined reporting or recovery path for the failure.
Which example is reuse rather than recovery?
Show answer and feedback
Answer: Checking out a returned stream under a new valid claim.
Why: Reuse establishes a new valid claim for an existing resource. The other options respond to failures and are recovery actions.
Cancellation and scene unload can both request cleanup. What evidence best demonstrates protection against double release?
Show answer and feedback
Answer: A state transition or guard permits owned claims to be released at most once.
Why: The lifecycle needs an observable state change or guard so multiple terminal events cannot release the same claim twice.