{"id":211,"date":"2024-02-06T11:45:00","date_gmt":"2024-02-06T14:45:00","guid":{"rendered":"https:\/\/suspensao.blog.br\/disbelief\/?p=211"},"modified":"2024-05-18T00:19:55","modified_gmt":"2024-05-18T03:19:55","slug":"implementing-malloc-and-free-reusing-memory-blocks","status":"publish","type":"post","link":"https:\/\/suspensao.blog.br\/disbelief\/implementing-malloc-and-free-reusing-memory-blocks\/","title":{"rendered":"Implementing malloc() and free() \u2014 reusing memory blocks"},"content":{"rendered":"\n<ol class=\"wp-block-list\">\n<li><\/li>\n\n\n\n<li>This post is part of a series on how to implement the <code>malloc()<\/code> and <code>free()<\/code> functions. In <a href=\"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-adicionando-metadados-ao-blocos-de-memoria\">a previous article<\/a>, we changed our functions to free up some memory blocks. However, this only occurred if the freed blocks were deallocated from newest to oldest.<\/li>\n<\/ol>\n\n\n\n<p>This wouldn&#8217;t make much difference. Dynamically allocated memory rarely behaves like a stack, where the newest block is always deallocated first. The big advantage of dynamic memory allocation, after all, is that it <em>doesn&#8217;t<\/em> work like a stack.<\/p>\n\n\n\n<p>To understand the limitations of our implementation, consider the code below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *ptr1 = abmalloc(8);<br>void *ptr2 = abmalloc(8);<br>abfree(ptr1);<br>void *ptr3 = abmalloc(8);<\/code><\/pre>\n\n\n\n<p>In the first line, we allocate eight bytes, and free them in the third line. In the last line, we allocate eight bytes again. However, we cannot reuse the freed memory. To truly save memory, we need a more sophisticated solution.<\/p>\n\n\n\n<p>One option is to reuse free blocks. To do this, we add a Boolean field to the block header, called <code>available<\/code>, which will indicate whether the block is free. As a block can only be reused if the memory requested by <code>abmalloc()<\/code> is less than or equal to that available in the block, we also need a field in the header indicating the size of the block, which we will call <code>size<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>typedef struct Header {\n  struct Header *previous;\n  size_t size;\n  bool available;\n} Header;<\/code><\/pre>\n\n\n\n<p>When the block is allocated, the value of the <code>available<\/code> field must be <code>false<\/code> (since the block is not available). We also record the block size in the <code>size<\/code> field:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *abmalloc(size_t size) {\n  Header *header = sbrk(sizeof(Header) + size);\n  header-&gt;previous = last;\n  header-&gt;size = size;\n  header-&gt;available = false;\n  last = header;\n  return last + 1;\n}<\/code><\/pre>\n\n\n\n<p>We have the information in the header but we are not yet reusing deallocated memory. To reuse the available blocks, we need to find them! The algorithm for this is very simple: <code>abmalloc()<\/code> will start iterating over the blocks, starting from the last until reaching the first. Since the <code>previous<\/code> pointer of the first block is always <code>NULL<\/code>, we stop when we find such value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *abmalloc(size_t size) {\n   Header *header = last;\n   while (header != NULL) {\n     header = header-&gt;previous;\n   }<\/code><\/pre>\n\n\n\n<p>In each iteration, we check whether the block is available and has an acceptable size. If in the middle of this process we find an available block greater than or equal to what we need, we got lucky! Just mark the block as unavailable, and return it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *abmalloc(size_t size) {<br>   Header *header = last;<br>   while (header != NULL) {<br>     if (header-&gt;available &amp;&amp; (header-&gt;size &gt;= size)) {<br>       header-&gt;available = false;<br>       return header + 1;<br>     }<br>     header = header-&gt;previous;<br>   }<\/code><\/pre>\n\n\n\n<p>What if we don&#8217;t find a block that satisfies these conditions? In this case, the <code>abmalloc()<\/code> function increases the heap, as it used to do:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void *abmalloc(size_t size) {\n  Header *header = last;\n  while (header != NULL) {\n    if (header-&gt;available &amp;&amp; (header-&gt;size &gt;= size)) {\n      header-&gt;available = false;\n      return header + 1;\n    }\n    header = header-&gt;previous;\n  }\n  header = sbrk(sizeof(Header) + size);\n  header-&gt;previous = last;\n  header-&gt;size = size;\n  header-&gt;available = false;\n  last = header;\n  return last + 1;\n}<\/code><\/pre>\n\n\n\n<p>When it comes to deallocating, we have two possible situations. If the block deallocated by <code>abfree()<\/code> is the last one, nothing changes: we move the top of the <em>heap<\/em> to the beginning of the block, we change the <code>last<\/code> pointer. But what if the block is <em>not<\/em> on top of the heap? We simply mark it as available, as can be seen in the <code>else<\/code> clause of the function below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void abfree(void *ptr) {\n   Header *header = (Header*) ptr - 1;\n   if (header == last) {\n     last = header-&gt;previous;\n     brk(header);\n   } else {\n     header-&gt;available = true;\n   }\n }<\/code><\/pre>\n\n\n\n<p>Reusing blocks of memory is a huge advance. However, we can be even more efficient in memory usage. For example, we only reduce the heap size if we deallocate the last block. If there are more unused blocks right before it, we could free them too. We will see how to do this in the next post.<\/p>\n\n\n\n<p><em>(This post is a translation of <a href=\"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-adicionando-metadados-aos-blocos-de-memoria\/\">Implementando malloc() and free() \u2014 reutilizando blocos de mem\u00f3ria<\/a>, originally published in <a href=\"https:\/\/suspensao.blog.br\/descrenca\">Suspens\u00e3o de Descren\u00e7a<\/a>.)<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dynamic memory allocation is of no use if we cannot reuse freed memory, right? Proceeding with our implementation, we will make our malloc() function use freed blocks of memory when possible!<\/p>\n","protected":false},"author":1,"featured_media":212,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[75,76],"tags":[77,82,80,78,47],"class_list":["post-211","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","category-linux","tag-c","tag-linux","tag-malloc","tag-memory-management","tag-software-development"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/suspensao.blog.br\/disbelief\/wp-content\/uploads\/2024\/01\/Mastrangelo_-_Reuse_-_2013.jpg?fit=1024%2C745&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9Ru6q-3p","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/posts\/211","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/comments?post=211"}],"version-history":[{"count":7,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/posts\/211\/revisions"}],"predecessor-version":[{"id":237,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/posts\/211\/revisions\/237"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/media\/212"}],"wp:attachment":[{"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/media?parent=211"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/categories?post=211"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/suspensao.blog.br\/disbelief\/wp-json\/wp\/v2\/tags?post=211"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}