jobjectpool
A lock-free object pool for Unity designed to reduce garbage collection through efficient instance reuse.
Install
mkdir -p .claude/skills/jobjectpool && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/3344" && unzip -o skill.zip -d .claude/skills/jobjectpool && rm skill.zipInstalls to .claude/skills/jobjectpool
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
JObjectPool thread-safe object pooling for Unity. Triggers on: object pool, GC optimization, reusable instances, bullet pool, enemy pool, effect pool, spawn pool, reduce garbage collection, memory optimization, pool prewarm, Rent Return pattern, lock-free poolKey capabilities
- →Rent and return objects from a pool
- →Pre-warm pools during loading
- →Reset object state on return
- →Manage shared pools for simple types
- →Reduce garbage collection in hot paths
How it works
It uses a lock-free, thread-safe system with CAS operations to manage a pool of reusable objects, allowing for rent/return cycles that minimize memory allocation.
Inputs & outputs
When to use jobjectpool
- →Pooling projectiles or bullet instances
- →Managing object reuse for visual effects
- →Optimizing enemy spawning to reduce GC
- →Pre-allocating objects to prevent memory spikes
About this skill
JObjectPool - Thread-Safe Object Pooling
Thread-safe, lock-free generic object pooling for Unity using CAS operations. Works with job system and async operations.
When to Use
- Frequently instantiated objects (bullets, enemies, effects)
- Reducing GC during gameplay
- Multi-threaded object reuse (safe from any thread)
- High-frequency object lifecycle operations
Core API
Constructor
new JObjectPool<T>(
int maxSize = 64, // Maximum pooled objects (excess discarded)
Action<T> onRent = null, // Called when renting (for initialization)
Action<T> onReturn = null // Called when returning (for cleanup)
)
Note: T must be a reference type with a parameterless constructor (where T : class, new()).
Methods
.Rent()- Get object from pool or create new.Return(T obj)- Return object to pool (null values ignored).Clear()- Remove all pooled objects.Prewarm(int count)- Pre-allocate objects (won't exceed maxSize).Count- Current available count (approximate, thread-safe)
Static Access
JObjectPool.Shared<T>()- Global shared pool per type (default config: maxSize=64)
Patterns
Basic Pool
var pool = new JObjectPool<Bullet>(maxSize: 100);
var bullet = pool.Rent();
// ... use bullet ...
pool.Return(bullet);
With Initialization on Rent
var pool = new JObjectPool<Enemy>(
maxSize: 50,
onRent: static enemy => enemy.Reset()
);
Reset State on Return (RECOMMENDED)
var pool = new JObjectPool<List<int>>(
maxSize: 32,
onReturn: static list => list.Clear()
);
Prewarm During Loading
var pool = new JObjectPool<Effect>();
pool.Prewarm(50); // Pre-create during loading screen
Shared Pool (Simple Objects)
// Good for simple reusable objects without custom callbacks
var sb = JObjectPool.Shared<StringBuilder>().Rent();
sb.Append("Hello");
sb.Clear(); // Clean up before returning
JObjectPool.Shared<StringBuilder>().Return(sb);
Game Patterns (Zero-GC)
Bullet Pool with Struct Config
public sealed class Bullet
{
public Vector3 Position;
public Vector3 Velocity;
public float Damage;
public float Lifetime;
public void Reset()
{
Position = default;
Velocity = default;
Damage = 0;
Lifetime = 0;
}
}
public sealed class BulletManager
{
private readonly JObjectPool<Bullet> _pool = new(
maxSize: 200,
onReturn: static b => b.Reset());
public void Initialize() => _pool.Prewarm(100);
public Bullet Fire(in Vector3 pos, in Vector3 dir, float speed, float damage)
{
var bullet = _pool.Rent();
bullet.Position = pos;
bullet.Velocity = dir * speed;
bullet.Damage = damage;
return bullet;
}
public void Return(Bullet b) => _pool.Return(b);
}
Enemy Spawner (Zero-GC State)
public sealed class Enemy : IPoolable
{
public float Health { get; set; }
public Vector3 Position { get; set; }
public event Action OnDeath;
public void OnSpawn()
{
Health = 100f;
}
public void OnDespawn()
{
OnDeath = null; // Clear delegates to prevent leaks
}
}
public sealed class EnemySpawner
{
private readonly JObjectPool<Enemy> _pool;
public EnemySpawner(int maxSize = 50)
{
_pool = new(
maxSize,
onRent: static e => e.OnSpawn(),
onReturn: static e => e.OnDespawn());
}
public Enemy Spawn(in Vector3 position)
{
var enemy = _pool.Rent();
enemy.Position = position;
return enemy;
}
public void Despawn(Enemy e) => _pool.Return(e);
}
Temporary Collection (Zero-GC in Update)
// Use in hot paths to avoid List<T> allocations
public void ProcessNearbyEnemies(in Vector3 center, float radius)
{
var list = JObjectPool.Shared<List<Enemy>>().Rent();
try
{
FindEnemiesNonAlloc(center, radius, list);
foreach (var enemy in list)
{
ProcessEnemy(enemy);
}
}
finally
{
list.Clear();
JObjectPool.Shared<List<Enemy>>().Return(list);
}
}
StringBuilder Pool (Zero-GC String Building)
public static string FormatDamage(float damage, string targetName)
{
var sb = JObjectPool.Shared<StringBuilder>().Rent();
try
{
sb.Append(targetName);
sb.Append(" took ");
sb.Append(damage.ToString("F1"));
sb.Append(" damage");
return sb.ToString();
}
finally
{
sb.Clear();
JObjectPool.Shared<StringBuilder>().Return(sb);
}
}
Best Practices
- Pre-allocate during loading to prevent in-game allocation spikes
- Reset state on return to prevent data leaks between reuses
- Set appropriate maxSize based on expected concurrent usage
- Use shared pools for simple objects without custom callbacks
- Monitor pool Count to optimize sizing
Troubleshooting
Objects Not Reused
- Forgot to Return: Always call
pool.Return(obj)when done - Pool at capacity: Increase maxSize if concurrent usage exceeds limit
- Returning null: Null values are silently ignored
Stale Data / Memory Leaks
- Not resetting state: Clear all fields in onReturn callback
- Event delegates: Unsubscribe all events in onReturn to prevent leaks
- References to disposed objects: Null out references in onReturn
Performance Issues
- Not pre-warming: Call
Prewarm()during loading screens - maxSize too low: Causes allocations when pool empties
- maxSize too high: Wastes memory
Thread Safety
- JObjectPool IS thread-safe (lock-free CAS)
- Safe to Rent/Return from any thread
- onRent/onReturn run on calling thread
Common Mistakes
- Returning null to pool (ignored, but wasteful)
- Not clearing object state on return (causes bugs from stale data)
- Forgetting to return objects (pool becomes ineffective)
- Setting maxSize too low (causes frequent allocations)
- Setting maxSize too high (wastes memory)
When not to use it
- →When objects are not frequently instantiated
- →When objects are not reference types
Limitations
- →Requires objects to have a parameterless constructor
- →Objects must be reference types
How it compares
It is specifically optimized for Unity's job system and async operations, providing a lock-free alternative to standard pooling.
Compared to similar skills
jobjectpool side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| jobjectpool (this skill) | 1 | 6mo | No flags | Advanced |
| nextjs-developer | 328 | 2mo | No flags | Advanced |
| sql-optimization-patterns | 64 | 2mo | No flags | Advanced |
| godot-gdscript-patterns | 57 | 4mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by JasonXuDeveloper
View all by JasonXuDeveloper →You might also like
nextjs-developer
zenobi-us
Expert Next.js developer mastering Next.js 14+ with App Router and full-stack features. Specializes in server components, server actions, performance optimization, and production deployment with focus on building fast, SEO-friendly applications.
sql-optimization-patterns
wshobson
Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.
godot-gdscript-patterns
sickn33
Master Godot 4 GDScript patterns including signals, scenes, state machines, and optimization. Use when building Godot games, implementing game systems, or learning GDScript best practices.
angular
sickn33
Modern Angular (v20+) expert with deep knowledge of Signals, Standalone Components, Zoneless applications, SSR/Hydration, and reactive patterns. Use PROACTIVELY for Angular development, component architecture, state management, performance optimization, and migration to modern patterns.
core-web-vitals
davila7
Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to "improve Core Web Vitals", "fix LCP", "reduce CLS", "optimize INP", "page experience optimization", or "fix layout shifts".
chrome-devtools
mrgoonie
Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.