Skip to content

Commit 1b68575

Browse files
committed
Object Pool Markdown changes
This commit includes proofreading changes to the Object Pool Markdown file.
1 parent 7d1e407 commit 1b68575

File tree

1 file changed

+39
-39
lines changed

1 file changed

+39
-39
lines changed

book/object-pool.markdown

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ of allocating and freeing them individually.*
1010

1111
We're working on the visual effects for our game. When the hero casts a spell,
1212
we want a shimmer of sparkles to burst across the screen. This calls for a
13-
*particle system*: an engine that spawns little sparkly graphics and animates
13+
*particle system*, an engine that spawns little sparkly graphics and animates
1414
them until they wink out of existence.
1515

1616
Since a single wave of the wand could cause hundreds of particles to be spawned,
@@ -20,19 +20,19 @@ need to make sure that creating and destroying these particles doesn't cause
2020

2121
### The curse of fragmentation
2222

23-
Programming for a game console like the XBox 360 is closer to embedded
23+
Programming for a game console like the Xbox 360 is closer to embedded
2424
programming than conventional PC programming in many ways. Like embedded
2525
programming, console games must run continuously for a very long time without
26-
crashing or leaking memory and efficient compacting memory managers are rarely
27-
available. In this environment memory fragmentation is deadly.
26+
crashing or leaking memory, and efficient compacting memory managers are rarely
27+
available. In this environment, memory fragmentation is deadly.
2828

2929
Fragmentation means the free space in our heap is <span
3030
name="park">broken</span> into smaller pieces of memory instead of one large
3131
open block. The *total* memory available may be large, but the largest
3232
*contiguous* region might be painfully small. Say we've got fourteen bytes free,
3333
but it's fragmented into two seven-byte pieces with a chunk of in-use memory
3434
between them. If we try to allocate a twelve-byte object, we'll fail. No more
35-
sparklies onscreen.
35+
sparklies on screen.
3636

3737
<aside name="park">
3838

@@ -48,7 +48,7 @@ free space is *fragmented* into bits of open curb between half a dozen cars.
4848

4949
<aside name="heap">
5050

51-
Here's how a heap becomes fragmented, and how it can cause an allocation to fail
51+
Here's how a heap becomes fragmented and how it can cause an allocation to fail
5252
even where there's theoretically enough memory available.
5353

5454
</aside>
@@ -61,41 +61,41 @@ and filled-in crevices, ultimately hosing the game completely.
6161

6262
Most console makers require games to pass "soak tests" where they leave the game
6363
running in demo mode for several days. If the game crashes, they don't allow it
64-
to ship. While soak tests sometimes fail because of a rarely-occurring bug, it's
64+
to ship. While soak tests sometimes fail because of a rarely occurring bug, it's
6565
usually creeping fragmentation or memory leakage that brings the game down.
6666

6767
</aside>
6868

6969
### The best of both worlds
7070

71-
Because of fragmentation, and because allocation may be slow, games are very
72-
careful about when and how they manage memory. A simple solution is often best:
73-
grab a big chunk of memory when the game starts and don't free it until the game
71+
Because of fragmentation and because allocation may be slow, games are very
72+
careful about when and how they manage memory. A simple solution is often best --
73+
grab a big chunk of memory when the game starts, and don't free it until the game
7474
ends. But this is a pain for systems where we need to create and destroy things
7575
while the game is running.
7676

77-
An object pool gives us the best of both worlds: to the memory manager, we're
77+
An object pool gives us the best of both worlds. To the memory manager, we're
7878
just allocating one big hunk of memory up front and not freeing it while the
7979
game is playing. To the users of the pool, we can freely allocate and deallocate
8080
objects to our heart's content.
8181

8282
## The Pattern
8383

8484
Define a **pool** class that maintains a collection of **reusable objects**.
85-
Each object supports an **"in use" query** to tell if it is currently "alive."
85+
Each object supports an **"in use" query** to tell if it is currently "alive".
8686
When the pool is initialized, it creates the entire collection of objects up
8787
front (usually in a single contiguous allocation) and initializes them all to
8888
the "not in use" state.
8989

9090
When you want a new object, ask the pool for one. It finds an available object,
91-
initializes it to "in use" and returns it. When the object is no longer needed,
91+
initializes it to "in use", and returns it. When the object is no longer needed,
9292
it is set back to the "not in use" state. This way, objects can be freely
9393
created and destroyed without needing to allocate memory or other resources.
9494

9595
## When to Use It
9696

9797
This pattern is used widely in games for obvious things like game entities and
98-
visual effects, but also for less visible data structures such as currently
98+
visual effects, but it is also used for less visible data structures such as currently
9999
playing sounds. Use Object Pool when:
100100

101101
* You need to frequently create and destroy objects.
@@ -110,7 +110,7 @@ playing sounds. Use Object Pool when:
110110

111111
## Keep in Mind
112112

113-
You normally rely on a garbage collector or just `new` and `delete` to handle
113+
You normally rely on a garbage collector or `new` and `delete` to handle
114114
memory management for you. By using an object pool, you're saying, "I know
115115
better how these bytes should be handled." That means the onus is on you to deal
116116
with this pattern's limitations.
@@ -124,14 +124,14 @@ smaller pool frees up memory that could be used for other fun stuff.
124124

125125
### Only a fixed number of objects can be active at any one time
126126

127-
In some ways this is a good thing. Partitioning memory into separate pools for
127+
In some ways, this is a good thing. Partitioning memory into separate pools for
128128
different types of objects ensures that, for example, a huge sequence of
129129
explosions won't cause your particle system to eat *all* of the available
130130
memory, preventing something more critical like a new enemy from being created.
131131

132132
Nonetheless, this also means being prepared for the possibility that your
133133
attempt to reuse an object from the pool will fail because they are all in use.
134-
There are a few common strategies to handle this.
134+
There are a few common strategies to handle this:
135135

136136
* *Prevent it outright.* This is the most common "fix": tune the pool sizes so
137137
that they never overflow regardless of what the user does. For pools of
@@ -154,7 +154,7 @@ There are a few common strategies to handle this.
154154

155155
* *Forcibly kill an existing object.* Consider a pool for currently playing
156156
sounds, and assume you want to start a new sound but the pool is full. You
157-
do *not* want to simply ignore the new sound: the user will notice if their
157+
do *not* want to simply ignore the new sound -- the user will notice if their
158158
magical wand swishes dramatically *sometimes* and stay stubbornly silent
159159
other times. A better solution is to find the quietest sound already playing
160160
and replace that with our new sound. The new sound will mask the audible
@@ -165,7 +165,7 @@ There are a few common strategies to handle this.
165165

166166
* *Increase the size of the pool.* If your game lets you be a bit more
167167
flexible with memory, you may be able to increase the size of the pool at
168-
runtime, or create a second overflow pool. If you do grab more memory in
168+
runtime or create a second overflow pool. If you do grab more memory in
169169
either of these ways, consider whether or not the pool should contract to
170170
its previous size when the additional capacity is no longer needed.
171171

@@ -228,7 +228,7 @@ the memory manager will usually deal with fragmentation for you. But pools are
228228
still useful there to avoid the cost of allocation and deallocation, especially
229229
on mobile devices with slower CPUs and simpler garbage collectors.
230230

231-
If you do use an object pool there, beware of a potential conflict. Since the
231+
If you do use an object pool along with a garbage collector, beware of a potential conflict. Since the
232232
pool doesn't actually deallocate objects when they're no longer in use, they
233233
remain in memory. If they contain references to *other* objects, it will prevent
234234
the collector from reclaiming those too. To avoid this, when a pooled object is
@@ -237,7 +237,7 @@ no longer in use, clear any references it has to other objects.
237237
## Sample Code
238238

239239
Real-world particle systems will often apply gravity, wind, friction, and other
240-
physical effects. Our much simpler sample will just move particles in a straight
240+
physical effects. Our much simpler sample will only move particles in a straight
241241
line for a certain number of frames and then kill the particle. Not exactly film
242242
caliber, but it should illustrate how to use an object pool.
243243

@@ -246,15 +246,15 @@ particle class:
246246

247247
^code 1
248248

249-
The default constructor initializes the particle to "not in use." A later call
249+
The default constructor initializes the particle to "not in use". A later call
250250
to `init()` initializes the particle to a live state.
251251

252252
Particles are animated over time using the unsurprisingly named `animate()`
253253
function, which should be called once per frame.
254254

255255
The pool needs to know which particles are available for reuse. It gets this
256-
from the particle's `inUse()` function. It takes advantage of the fact that
257-
particles have a limited lifetime, and uses the `_framesLeft` variable to
256+
from the particle's `inUse()` function. This function takes advantage of the fact that
257+
particles have a limited lifetime and uses the `_framesLeft` variable to
258258
discover which particles are in use without having to store a separate flag.
259259

260260
The pool class is also simple:
@@ -275,7 +275,7 @@ class="pattern">Update Method</a> pattern.
275275
The particles themselves are simply stored in a fixed-size array in the class.
276276
In this sample implementation, the pool size is hardcoded in the class
277277
declaration, but this could be defined externally by using a dynamic array of a
278-
given size, or using a value template parameter.
278+
given size or by using a value template parameter.
279279

280280
Creating a new particle is straightforward:
281281

@@ -286,7 +286,7 @@ find it, we initialize it and we're done. Note that in this implementation, if
286286
there aren't any available particles, we simply don't create a new one.
287287

288288
That's all there is to a simple particle system, aside from rendering the
289-
particles, of course. We can now create a pool, and create some particles using
289+
particles, of course. We can now create a pool and create some particles using
290290
it. The particles will automatically deactivate themselves when their lifetime
291291
has expired.
292292

@@ -307,7 +307,7 @@ algorithms class.
307307

308308
If we don't want to waste time *finding* free particles, the obvious answer is
309309
to not lose track of them. We could store a separate list of pointers to each
310-
unused particle. Then, when we need to create a particle, we just remove the
310+
unused particle. Then, when we need to create a particle, we remove the
311311
first pointer from the list and reuse the particle it points to.
312312

313313
Unfortunately, this would require us to maintain an entire separate array with
@@ -316,7 +316,7 @@ create the pool, *all* particles are unused, so the list would initially have a
316316
pointer to every object in the pool.
317317

318318
It would be nice to fix our performance problems *without* sacrificing any
319-
memory. Conveniently, there is some memory already lying around we can borrow:
319+
memory. Conveniently, there is some memory already lying around that we can borrow --
320320
the data for the unused particles themselves.
321321

322322
When a particle isn't in use, most of its state is irrelevant. Its position and
@@ -326,7 +326,7 @@ other bits can be reused. Here's a revised particle:
326326

327327
^code 4
328328

329-
We've gotten all of the member variables except for `framesLeft_` and moved them
329+
We've moved all of the member variables except for `framesLeft_`
330330
into a `live` struct inside a `state_` <span name="union">union</span>. This
331331
struct holds the particle's state when it's being animated. When the particle is
332332
unused, the other case of the union, the `next` member, is used. It holds a
@@ -336,15 +336,15 @@ pointer to the next available particle after this one.
336336

337337
Unions don't seem to be used that often these days, so the syntax may be
338338
unfamiliar to you. If you're on a game team, you've probably got a "memory
339-
guru," that beleaguered compatriot whose job it is to come up with a solution
339+
guru", that beleaguered compatriot whose job it is to come up with a solution
340340
when the game has inevitably blown its memory budget. Ask them about unions.
341341
They'll know all about them and other fun bit-packing tricks.
342342

343343
</aside>
344344

345345
We can use these pointers to build a linked list that chains together every
346346
unused particle in the pool. We have the list of available particles we need,
347-
but didn't need to use any additional memory. Instead, we cannibalize the memory
347+
but we didn't need to use any additional memory. Instead, we cannibalize the memory
348348
of the dead particles themselves to store the list.
349349

350350
This clever technique is called a [*free
@@ -360,7 +360,7 @@ list should thread through the entire pool. The pool constructor sets that up:
360360

361361
^code 6
362362

363-
Now to create a new particle, we just jump directly to the <span
363+
Now to create a new particle, we jump directly to the <span
364364
name="first">first</span> available one:
365365

366366
<aside name="first">
@@ -377,7 +377,7 @@ up the ghost in that frame:
377377

378378
^code particle-animate
379379

380-
When that happens, we just thread it back onto the list:
380+
When that happens, we simply thread it back onto the list:
381381

382382
^code 8
383383

@@ -406,7 +406,7 @@ objects.
406406

407407
* *You can ensure that the objects can only be created by the pool.* In
408408
C++, a simple way to do this is to make the pool class a friend of the
409-
object class, and then make the object's constructor private.
409+
object class and then make the object's constructor private.
410410

411411
^code 10
412412

@@ -428,7 +428,7 @@ objects.
428428
reusable pool class.
429429

430430
* *The "in use" state must be tracked outside the objects.* The simplest
431-
way to do this is by creating a separate bit field.
431+
way to do this is by creating a separate bit field:
432432

433433
^code 11
434434

@@ -456,20 +456,20 @@ outside.
456456

457457
* *The pool's interface can be simpler.* Instead of offering multiple
458458
functions to cover each way an object can be initialized, the pool can
459-
simply return a reference to the new object.
459+
simply return a reference to the new object:
460460

461461
^code 13
462462

463463
The caller can then initialize the object by calling any method the
464-
object exposes.
464+
object exposes:
465465

466466
^code 14
467467

468468
* *Outside code may need to handle the failure to create a new object.*
469469
The previous example assumes that `create()` will always successfully
470470
return a pointer to an object. If the pool is full, though, it may
471471
return `NULL` instead. To be safe, you'll need to check for that before
472-
you try to initialize the object.
472+
you try to initialize the object:
473473

474474
^code 15
475475

@@ -478,7 +478,7 @@ outside.
478478
* This looks a lot like the <a class="gof-pattern" href="flyweight.html">
479479
Flyweight</a> pattern. Both maintain a collection of reusable objects. The
480480
difference is what "reuse" means. Flyweight objects are reused by sharing
481-
the same instance between multiple owners *simultaneously*. It avoids
481+
the same instance between multiple owners *simultaneously*. The Flyweight pattern avoids
482482
*duplicate* memory usage by using the same object in multiple contexts.
483483

484484
The objects in a pool get reused too, but only over time. "Reuse" in the

0 commit comments

Comments
 (0)