Audit resource management including IDisposable pattern implementation, proper cleanup of OpenGL resources (buffers, textures, shaders, framebuffers), memory leak detection, resource lifetime management, and GPU resource tracking. Use when investigating memory leaks, GPU resource exhaustion, or implementing new resource types.
This skill audits resource management to ensure proper cleanup of OpenGL resources, correct IDisposable implementation, and prevention of memory leaks. Focus on engine-specific concerns like OpenGL context safety, factory ownership patterns, and GPU resource tracking.
Invoke this skill when:
Why: OpenGL context is NOT available on finalizer thread. Calling GL functions in finalizers causes crashes.
// ✅ CORRECT - Log warning instead
~Texture()
{
if (_rendererID != 0)
{
Logger.Error($"Texture {_path} not disposed! GPU leak.");
// Do NOT call GL.DeleteTexture here!
}
}
public void Dispose()
{
if (_rendererID != 0)
{
GL.DeleteTexture(_rendererID); // Safe - correct thread
_rendererID = 0;
}
GC.SuppressFinalize(this); // Prevent finalizer
}
Rule: Factory owns cached resources. Consumers get references but don't dispose them.
// TextureFactory owns and disposes cached textures
var texture = _textureFactory.Load("sprite.png");
// ❌ WRONG - Don't dispose factory-managed resources
texture.Dispose(); // Other users still need this!
// ✅ CORRECT - Factory disposes on shutdown
// Just use the texture, factory handles lifetime
Check ownership documentation in resource classes (see XML comments).
Owned: Component creates resource exclusively for itself → Component disposes it Shared: Resource comes from factory/cache → Factory disposes it
public class MeshRenderer : IDisposable
{
private Mesh _mesh; // Shared (factory-managed)
private uint _instanceVBO; // Owned (created by this component)
public void Dispose()
{
// Don't dispose _mesh (shared)
// DO dispose _instanceVBO (owned)
if (_instanceVBO != 0)
{
GL.DeleteBuffer(_instanceVBO);
_instanceVBO = 0;
}
}
}
Always implement these safeguards:
public class Texture : IDisposable
{
private uint _rendererID;
private bool _disposed = false;
public void Dispose()
{
if (_disposed) // 1. Guard double-disposal
return;
if (_rendererID != 0) // 2. Check resource exists
{
GL.DeleteTexture(_rendererID);
_rendererID = 0; // 3. Reset to prevent re-delete
}
_disposed = true;
GC.SuppressFinalize(this); // 4. Skip finalizer
}
}
When reviewing resource-owning classes, verify:
IDisposable_disposed flag to guard double-disposalGC.SuppressFinalize(this) in Dispose()new Texture() has clear disposal pathGL.GenBuffer() has matching GL.DeleteBuffer()using or try-finally)See references/anti-patterns.cs for detailed examples. Quick reference:
_disposed guard → Crashes on second Dispose()_mesh.Dispose() crashes if null → Use _mesh?.Dispose()using statementStandard IDisposable patterns with engine-specific notes: references/disposal-patterns.cs
Pattern Selection:
When reporting audit findings:
**Issue**: [Resource management problem]
**Location**: [File:line]
**Resource Type**: [OpenGL buffer/texture/shader/etc.]
**Problem**: [Specific issue - leak, double disposal, missing cleanup]
**Recommendation**:
[Code example showing fix]
**Priority**: [Critical/High/Medium/Low]
Example:
**Issue**: Mesh resources not disposed when entity destroyed
**Location**: Engine/Scene/Entity.cs:89
**Resource Type**: OpenGL VBO, EBO, VAO
**Problem**: Entity.Destroy() doesn't dispose MeshComponent.Mesh,
causing GPU memory leak (20MB per load/unload cycle)
**Recommendation**:
public void Destroy()
{
if (HasComponent<MeshComponent>())
{
var meshComp = GetComponent<MeshComponent>();
// Only dispose if component owns the mesh (not factory-managed)
if (meshComp.OwnsMesh)
{
meshComp.Mesh?.Dispose();
}
meshComp.Mesh = null;
}
_scene.RemoveEntity(this);
}
**Priority**: High (GPU memory leak)
references/disposal-patterns.cs: Standard IDisposable patterns (basic, full, factory)references/anti-patterns.cs: 8 common mistakes with ❌/✅ examplesCore Principles:
_disposed flagGC.SuppressFinalize(this) in Dispose()Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer