Object pool
The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "pool" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than destroying it. This can offer a significant performance boost in situations where the cost of initializing and destroy a class instance and prevent memory fragmentation.
Memory fragmentation
Memory fragmentation is a condition where memory is divided into small, non-contiguous blocks. This can happen when memory is allocated and deallocated in a random order. This can lead to a situation where the memory is not used efficiently. The memory is fragmented into small blocks, but the program needs a large block of memory. This can lead to a situation where the program runs out of memory, even though there is enough memory available.

Object Pool Pattern
Fragmentation and allocation/deallocation of memory can be expensive. There is a simple solution is that grab a big chunk of memory when the game starts, and don't free it until the game ends.
Here is a simple example of an object pool that creates a pool of bullets. The pool is created with a class that represents the object to be pooled. The pool has a method to get an object from the pool and a method to release an object back to the pool.
class ObjectPool {
constructor(ObjectClass) {
this.ObjectClass = ObjectClass;
this._pool = [];
}
get() {
if (this._pool.length > 0) {
return this._pool.pop();
}
return new this.ObjectClass();
}
release(obj) {
this._pool.push(obj);
}
clear() {
this._pool = [];
}
}
class GameObject {
constructor() {
this.x = 0;
this.y = 0;
this.active = false;
}
}
class Bullet extends GameObject {
constructor() {
super();
this.speed = 5;
}
update(dt) {
this.x += this.speed * dt;
}
}
const bulletPool = new ObjectPool(Bullet);
const bullets = [];
let timeCounter = 0;
function update(dt) {
timeCounter += dt;
// spawn bullets every second
if (timeCounter >= 1) {
spawnBullets();
timeCounter = 0;
}
// update bullets and despawn them if they are out of the screen
for (let i = 0; i < bullets.length; i++) {
const bullet = bullets[i];
bullet.update(dt);
if (bullet.x > 800) {
bullet.active = false;
bulletPool.release(bullet);
bullets.splice(i, 1);
i--;
}
}
}
function spawnBullets() {
// spawn from 1 to 10 bullets
let numBullets = Math.random() * 10;
for (let i = 0; i < numBullets; i++) {
const bullet = bulletPool.get();
bullet.active = true;
bullet.y = Math.random() * 800;
bullets.push(bullet);
}
}