<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Memory on Roberto Selbach</title><link>https://rselbach.com/tags/memory/</link><description>Recent content in Memory on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Thu, 21 May 2009 21:08:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/memory/index.xml" rel="self" type="application/rss+xml"/><item><title>The Allocator Is Part of the Program</title><link>https://rselbach.com/the-allocator-is-part-of-the-program/</link><pubDate>Thu, 21 May 2009 21:08:00 +0000</pubDate><guid>https://rselbach.com/the-allocator-is-part-of-the-program/</guid><description>&lt;p&gt;A multithreaded parser scaled nicely to two workers and then barely improved. I inspected locks in my code and found no obvious villain. Eventually a profile pointed at allocation and deallocation, which felt unfair because &lt;code&gt;malloc()&lt;/code&gt; had not appeared on my list of interesting algorithms.&lt;/p&gt;
&lt;p&gt;An allocator manages more than a pointer advancing through memory. It finds suitably sized free regions, records metadata, returns memory to reusable pools and sometimes asks the operating system for more pages. In multiple threads it must also protect shared structures. A program creating millions of short-lived objects can therefore spend substantial time contending inside code it never explicitly called.&lt;/p&gt;
&lt;p&gt;The system allocator already uses techniques to reduce this cost. Implementations may maintain size classes, bins and multiple arenas so not every allocation takes one global lock. Alternative allocators such as tcmalloc and jemalloc make different tradeoffs involving per-thread caches, fragmentation and concurrency. Swapping one in can be an excellent experiment, but it is not a substitute for understanding the allocation pattern.&lt;/p&gt;
&lt;p&gt;My parser allocated a small object for every token, then freed the whole tree after processing a request. The lifetimes were almost identical. A simple region allocator fit better: reserve larger blocks, hand out aligned pieces by moving a pointer, and release the region at once when the request completes. Individual deallocation disappears because the ownership model says nothing outlives the request.&lt;/p&gt;
&lt;p&gt;This improved both speed and clarity. The gain did not come from a magical allocator; it came from expressing lifetime in the data structure. It also introduced a strict rule: pointers into the region cannot escape. Violating that rule turns cleanup into a mass dangling-pointer production line, which is efficient in the wrong direction.&lt;/p&gt;
&lt;p&gt;Object pools are useful when objects have uniform shape and repeated lifetimes, but I use them cautiously. A pool retains memory, complicates construction and may conceal an unbounded queue. Per-thread caches can reduce contention while increasing total memory consumption. Peak resident size matters as much as allocations per second on a shared machine.&lt;/p&gt;
&lt;p&gt;Measurement must include realistic concurrency and duration. A short benchmark can reward an allocator for keeping every page. A long-running service eventually reveals fragmentation and cache growth. I watch CPU profiles, allocation counts and resident memory rather than treating one throughput number as a complete biography.&lt;/p&gt;
&lt;p&gt;I prefer changing ownership and allocation frequency before replacing the general allocator. When patterns are genuinely general and contention remains measurable, testing another mature allocator is reasonable. In this case, the region was the stronger result because it made the program&amp;rsquo;s lifetime visible. I had gone looking for a faster &lt;code&gt;malloc()&lt;/code&gt; and found that asking for less was cheaper.&lt;/p&gt;</description></item><item><title>QObject Ownership Is Not Garbage Collection</title><link>https://rselbach.com/qobject-ownership-is-not-garbage-collection/</link><pubDate>Fri, 18 Mar 2005 18:25:00 +0000</pubDate><guid>https://rselbach.com/qobject-ownership-is-not-garbage-collection/</guid><description>&lt;p&gt;I found a leak in a small Qt 3.3 dialog and responded by deleting every child widget in the destructor. Then I noticed that the widgets already had the dialog as their parent. My heroic cleanup was redundant; the actual leak was an object with no parent at all.&lt;/p&gt;
&lt;p&gt;Qt&amp;rsquo;s object trees are straightforward once I stop pretending they are magic. A &lt;code&gt;QObject&lt;/code&gt; with a parent joins that parent&amp;rsquo;s child list. Destroying the parent destroys its children. Top-level objects and objects without parents remain my responsibility.&lt;/p&gt;
&lt;p&gt;My useful check is now mechanical. At construction, I ask who owns each allocation. If the answer is a parent object, I do not delete it separately. If there is no parent, I give the lifetime an explicit home in C++ code. Layouts arrange widgets; they do not replace ownership reasoning.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;QLabel &lt;span style="color:#f92672"&gt;*&lt;/span&gt;label &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; QLabel(tr(&lt;span style="color:#e6db74"&gt;&amp;#34;Status&amp;#34;&lt;/span&gt;), &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here &lt;code&gt;this&lt;/code&gt; is the relevant part, not &lt;code&gt;new&lt;/code&gt;. The parent makes the intended lifetime visible and ties cleanup to the dialog.&lt;/p&gt;
&lt;p&gt;This is not garbage collection. Qt does not discover arbitrary unreachable C++ objects, and a parent cannot rescue a dangling pointer used after destruction. It is a disciplined ownership convention layered over C++.&lt;/p&gt;
&lt;p&gt;The conclusion is pleasantly small: establish one owner and make it obvious at construction. My destructor became shorter, which is about the nicest possible result of debugging C++ memory management.&lt;/p&gt;</description></item></channel></rss>