Skip to content

Commit 15afd9a

Browse files
authored
Merge pull request #46 from rpoyner-tri/mem-alloc
cppguide: Update memory allocation advice
2 parents 5e805eb + c2a6889 commit 15afd9a

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

cppguide.html

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,11 +2213,52 @@ <h3 id="Doxygen">Doxygen</h3>
22132213
<h3 id="Memory Allocation">Memory Allocation</h3>
22142214

22152215
<div class="summary">
2216-
<p>No dynamic allocation in the inner simulation/control loops. Code should
2217-
be still be thread-safe (e.g. be careful with pre-allocations).
2216+
<p>It's often important to avoid dynamic memory allocation within
2217+
performance-critical code regions (e.g., simulation steps, control loops). Code
2218+
that pre-allocates must be thread-safe, within common Drake thread use idioms
2219+
(see below). Performance-critical code that promises to avoid allocations must
2220+
have an automated acceptance test using the the Drake
2221+
<a href="https://github.com/RobotLocomotion/drake/blob/master/common/test_utilities/limit_malloc.h">LimitMalloc</a>
2222+
tool.
22182223
</p>
22192224
</div>
22202225

2226+
<div class="stylebody">
2227+
2228+
<p>Pre-allocating memory for use in high-performance code avoids potentially
2229+
expensive operations to obtain memory from the heap. Importantly, since the
2230+
heap is a process-global resource, heap operations can incur synchronization
2231+
costs, such as waiting on a mutex. So, heap operations are not only expensive,
2232+
but also have a non-deterministic run-time cost.</p>
2233+
2234+
<p>In some situations, it may be necessary to allocate memory inside a function
2235+
executed in a performance-critical loop. This may be acceptable if that
2236+
initialization occurs in the first few loop invocations and the function
2237+
subsequently ceases to allocate.</p>
2238+
2239+
<p>One big advantage of conventional heap operations (e.g. a std::vector as a
2240+
function-local variable) is that they <i>are</i> thread-safe, and their wide
2241+
use ensures that the implementations are efficient and high-quality. When
2242+
pre-allocating, the code is likely to reuse the storage in less common ways. Be
2243+
careful to avoid situations where the storage could be accessed from multiple
2244+
threads without synchronization.</p>
2245+
2246+
<h4>Systems, Contexts, and Threading</h4>
2247+
2248+
<p>In Drake, the most common thread use idiom is the single-system,
2249+
multiple-context idiom. Multiple threads each own a Drake context, and they
2250+
reuse a shared system (or diagram). To support this, system (or diagram)
2251+
classes must only store data necessary to maintain the structure of the system,
2252+
but not any data related to computation of inputs, outputs, or system state. If
2253+
persistent storage is needed to compute without requiring heap operations, that
2254+
storage should be obtained via a Drake cache entry. Cache entries will be
2255+
allocated on a per-context basis, so that there is no thread safety hazard when
2256+
using context-per-thread multithreading. An example of this technique can be
2257+
found in <a href="https://github.com/RobotLocomotion/drake/pull/14929">PR
2258+
#14929</a>.</p>
2259+
2260+
</div>
2261+
22212262
</div>
22222263

22232264
<h3 id="Ownership_and_Smart_Pointers">Ownership and Smart Pointers</h3>

0 commit comments

Comments
 (0)