{"id":21,"date":"2014-07-26T20:46:02","date_gmt":"2014-07-26T20:46:02","guid":{"rendered":"http:\/\/www.jacobpike.com\/blog\/?p=21"},"modified":"2014-07-26T20:51:57","modified_gmt":"2014-07-26T20:51:57","slug":"fixing-memory-usage-issue-for-noahs-ark","status":"publish","type":"post","link":"http:\/\/www.jacobpike.com\/blog\/2014\/07\/26\/fixing-memory-usage-issue-for-noahs-ark\/","title":{"rendered":"Fixing Memory Usage Issue for Noah&#8217;s Ark"},"content":{"rendered":"<p>I recently ran into a memory usage defect for my <a href=\"https:\/\/github.com\/jpike\/noah_ark\">Noah&#8217;s Ark game<\/a>. Basically, as the player scrolled to different tile maps in the overworld, memory usage would continue to climb, eventually bringing the game to a crawl. The fix was really simple but involved some more subtleties of C++ smart pointers, so it seemed worth writing about.<\/p>\n<p><strong>Graphics Management<\/strong><br \/>\nFirst, it is important to understand how graphics are currently managed in the game code. Different types of <a href=\"https:\/\/github.com\/jpike\/noah_ark\/blob\/master\/noah_ark\/library\/noah_ark_library\/src\/Graphics\/IGraphicsComponent.h\">graphics components<\/a> are created from the <code><a href=\"https:\/\/github.com\/jpike\/noah_ark\/blob\/master\/noah_ark\/library\/noah_ark_library\/src\/Graphics\/GraphicsSystem.h\">GraphicsSystem<\/a><\/code>. The <code>GraphicsSystem<\/code> is then responsible for rendering all of the graphics on screen.<\/p>\n<p>I&#8217;m not necessarily sure this is the &#8220;best design&#8221; for the game (if you have other ideas, feel free to suggest them!). It is just something I&#8217;m experimenting with from various things I&#8217;ve read (mostly on entity component systems or ways to avoid having all of my game objects have explicit render methods). My main goal was to be able to easily apply global settings to all of the rendered graphics without having to touch a bunch of classes. Time will tell how well this works out.<\/p>\n<p><strong>Map Scrolling<\/strong><br \/>\nThe second major piece of the puzzle is to understand how the game scrolls between individual tile maps in the overworld. At any given time, the <code><a href=\"https:\/\/github.com\/jpike\/noah_ark\/blob\/master\/noah_ark\/library\/noah_ark_library\/src\/Maps\/OverworldMap.h\">OverworldMap<\/a><\/code> holds the current, top, bottom, left, and right <code><a href=\"https:\/\/github.com\/jpike\/noah_ark\/blob\/master\/noah_ark\/library\/noah_ark_library\/src\/Maps\/TileMap.h\">TileMaps<\/a><\/code> (assuming they exist):<\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.jacobpike.com\/blog\/wp-content\/uploads\/2014\/07\/noah_ark_surrounding_maps1.png\" alt=\"The tile maps in memory at any given time in the Noah's Ark game.\" \/><\/p>\n<p>When the player reaches the edge of the current map, the game scrolls to the appropriate adjacent map (if one exists), and then reloads any new maps surrounding this new map being scrolled to.<\/p>\n<p><strong>The Bug<\/strong><br \/>\nThere is a bit of a problem with the above approach, if you look at the details of the specific data types used. The graphics components created by the <code>GraphicsSystem<\/code> are returned as <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/shared_ptr\">shared_ptrs<\/a><\/code> and were (before the fix) also being stored as <code>shared_ptrs<\/code> in the <code>GraphicsSystem<\/code> class. These <code>shared_ptrs<\/code> are then used by whatever objects the graphics are for. In this case, these <code>shared_ptrs<\/code> were also used by <code><a href=\"https:\/\/github.com\/jpike\/noah_ark\/blob\/master\/noah_ark\/library\/noah_ark_library\/src\/Maps\/Tile.h\">Tiles<\/a><\/code> in the <code>TileMap<\/code> class.<\/p>\n<p>When scrolling to new <code>TileMaps<\/code>, the old <code>TileMaps<\/code> would be destructed, decrementing the reference counts for the <code>shared_ptrs<\/code> for <code>Tiles<\/code> in the map. However, since the <code>GraphicsSystem<\/code> still stored these <code>shared_ptrs<\/code> for the tile graphics, the reference count would still be 1, so the tile graphics would persist in memory. New maps would be loaded, creating new tile graphics components, but all of the old tiles would still exist. Obviously, this is problematic and leads to increasing memory usage over time, which ended up slowing the game to a crawl.<\/p>\n<p><strong>The Solution<\/strong><br \/>\nI actually was aware of this problem during original implementation of the design outlined above but forgot about it by the time the defect actually manifested itself. This was a pretty major architecture problem, but I didn&#8217;t want to abandon the idea of having a centralized place (away from the main game objects) to control rendering.<\/p>\n<p>I couldn&#8217;t use <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/unique_ptr\">unique_ptrs<\/a><\/code> since the graphics components needed to be accessible by both the <code>GraphicsSystem<\/code> and the individual objects the graphics are for. There are ways around this, such as using raw pointers, but that would make communicating when the resources were to be deleted from the <code>GraphicsSystem<\/code> pretty ugly (I also don&#8217;t like the lack of clarity that raw pointers can present when reading code, but that is for another blog post).<\/p>\n<p>Fortunately, C++ had an elegant solution. Enter the <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/weak_ptr\">weak_ptr<\/a><\/code>. The description on the linked page is best to read for an understanding (and examples help), but a <code>weak_ptr<\/code> allowed me to break the &gt; 0 reference count problem described above in a pretty nice way.<\/p>\n<p>When an object like a <code>Tile<\/code> (part of a <code>TileMap<\/code>) is destructed, I wanted it to communicate to the <code>GraphicsSystem<\/code> that the graphics for the <code>Tile<\/code> could be deleted. To accomplish this, I made the following changes:<\/p>\n<p>The <code>GraphicsSystem<\/code> was changed to store its graphics components as <code>weak_ptrs<\/code> instead of <code>shared_ptrs<\/code>:<\/p>\n<p style=\"text-align: center;\"><code>std::list&lt; std::weak_ptr&lt;IGraphicsComponent&gt; &gt; m_graphicsComponents;<\/code><\/p>\n<p>One nice thing is that the <code>weak_ptr<\/code> class has a constructor that allows it to be constructed from a <code>shared_ptr<\/code>, meaning I didn&#8217;t have to touch the code that added items to the above container.<\/p>\n<p>Next, I had to update the <code>for<\/code> loops that iterated over the graphics components to use <code>weak_ptrs<\/code> instead of <code>shared_ptrs<\/code>. Before updating\/rendering an individual graphics component, I needed to check if the object had already been deleted elsewhere (i.e. the <code>Tile<\/code> destructor) using the <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/weak_ptr\/expired\">expired<\/a><\/code> method:<\/p>\n<p style=\"text-align: center;\"><code>if (!graphicsComponentWeakReference.expired())<\/code><\/p>\n<p>(See the Wikipedia page for an overview of the concept of <a href=\"http:\/\/en.wikipedia.org\/wiki\/Weak_reference\">weak references<\/a>.)<\/p>\n<p>Assuming that the <code>weak_ptr<\/code> hasn&#8217;t expired, then the <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/weak_ptr\/lock\">lock<\/a><\/code> method can be called to obtain a usable <code>shared_ptr<\/code> to the object:<\/p>\n<p style=\"text-align: center;\"><code>std::shared_ptr&lt;IGraphicsComponent&gt; graphicsComponent = graphicsComponentWeakReference.lock();<\/code><\/p>\n<p>Tada! We&#8217;re almost done. The above code allows for checking if a graphics component has been deleted elsewhere, but it doesn&#8217;t actually solve the problem of increasing memory usage. The <code>weak_ptrs<\/code> are still stored in the list, so they need to be removed at some point. Fortunately, the <code>list<\/code> container has a <code><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/container\/list\/remove\">remove_if<\/a><\/code> that allows us to easily remove elements from the container that meet a certain condition (without resorting to the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Erase-remove_idiom\">erase-remove idiom<\/a>). Removing\u00a0the expired graphics components can be done in what is effectively a single line of code:<\/p>\n<p style=\"text-align: center;\"><code>m_graphicsComponents.remove_if([](std::weak_ptr&lt;IGraphicsComponent&gt;&amp; graphicsComponent) { return graphicsComponent.expired(); });<\/code><\/p>\n<p>That&#8217;s it! You can browse the full set of changes for this fix <a href=\"https:\/\/github.com\/jpike\/noah_ark\/commit\/0196c14e99ec0ff48d9158b577abb65ce6827f69\">here<\/a>. Finding and fixing this bug was a good learning experience for me, so hopefully it will be of use to some of you.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently ran into a memory usage defect for my Noah&#8217;s Ark game. Basically, as the player scrolled to different tile maps in the overworld, memory usage would continue to climb, eventually bringing the game to a crawl. The fix was really simple but involved some more subtleties of C++ smart pointers, so it seemed &hellip; <a href=\"http:\/\/www.jacobpike.com\/blog\/2014\/07\/26\/fixing-memory-usage-issue-for-noahs-ark\/\" class=\"more-link\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[10,8,11],"class_list":["post-21","post","type-post","status-publish","format-standard","hentry","category-noahs-ark-game","tag-memory","tag-noahs-ark","tag-pointers"],"_links":{"self":[{"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/posts\/21","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/comments?post=21"}],"version-history":[{"count":2,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/posts\/21\/revisions"}],"predecessor-version":[{"id":24,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/posts\/21\/revisions\/24"}],"wp:attachment":[{"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/media?parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/categories?post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.jacobpike.com\/blog\/wp-json\/wp\/v2\/tags?post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}