{"id":609,"date":"2024-01-22T11:15:00","date_gmt":"2024-01-22T14:15:00","guid":{"rendered":"https:\/\/suspensao.blog.br\/descrenca\/?p=609"},"modified":"2025-03-17T18:22:38","modified_gmt":"2025-03-17T21:22:38","slug":"implementando-malloc-e-free-adicionando-metadados-aos-blocos-de-memoria","status":"publish","type":"post","link":"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-adicionando-metadados-aos-blocos-de-memoria\/","title":{"rendered":"Implementando malloc() e free() \u2014 adicionando metadados aos blocos de mem\u00f3ria"},"content":{"rendered":"\n<p>Este post faz parte de uma s\u00e9rie sobre como implementar as fun\u00e7\u00f5es <code>malloc()<\/code> e <code>free()<\/code>. Anteriormente, <a href=\"https:\/\/suspensao.blog.br\/descrenca\/malloc-free-1\/\">fizemos uma implementa\u00e7\u00e3o s\u00e3o simpl\u00f3ria<\/a> que praticamente n\u00e3o libera mem\u00f3ria nenhuma: um ponteiro aponta para o \u00faltimo bloco alocado, o que permite que ab<code>free()<\/code> o desaloque, mas somente ele.<\/p>\n\n\n\n<p>Uma op\u00e7\u00e3o melhor \u00e9 fazer o \u00faltimo bloco apontar para o pen\u00faltimo, o pen\u00faltimo para o antepen\u00faltimo e assim por diante, formando uma <a href=\"https:\/\/pt.wikipedia.org\/wiki\/Lista_ligada\">lista ligada<\/a>. Para isso, criamos uma struct que servir\u00e1 como cabe\u00e7alho dos blocos, contendo um ponteiro para o bloco anterior:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">typedef struct Header {\n  struct Header *previous;\n} Header;<\/pre>\n\n\n\n<p>Al\u00e9m disso, o ponteiro para o \u00faltimo bloco, que era do tipo <code>void*<\/code>, agora \u00e9 do tipo <code>Header*<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Header *last = NULL;<\/pre>\n\n\n\n<p>Para usar esses cabe\u00e7alhos, <code>abmalloc()<\/code> reserva mem\u00f3ria suficiente para armazenar tanto o cabe\u00e7alho quanto o tamanho solicitado:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void *abmalloc(size_t size) {<br>  Header *header = sbrk(sizeof(Header) + size);<\/pre>\n\n\n\n<p>Deste modo, utilizamos o in\u00edcio do bloco para armazenar informa\u00e7\u00f5es necess\u00e1rias, como um ponteiro para o \u00faltimo bloco alocado antes do novo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">  header-&gt;previous = last;<\/pre>\n\n\n\n<p>Em seguida, atualizamos <code>last<\/code> para apontar para o novo bloco:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">   last = header;<\/pre>\n\n\n\n<p>Por fim, retornamos um ponteiro para a mem\u00f3ria que o usu\u00e1rio pode utilizar. Como <code>header<\/code> aponta para os metadados, n\u00e3o podemos simplesmente retorn\u00e1-lo. Caso contr\u00e1rio, toda informa\u00e7\u00e3o do cabe\u00e7alho seria sobrescrita quando o usu\u00e1rio usasse o ponteiro! Ao inv\u00e9s disso, retornamos um ponteiro para logo depois do cabe\u00e7alho. Este ponteiro \u00e9 f\u00e1cil de calcular: \u00e9 o endere\u00e7o de mem\u00f3ria do cabe\u00e7alho <em>mais<\/em> o tamanho do cabe\u00e7alho:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">  return header + 1;<br>}<\/pre>\n\n\n\n<p>Note como incrementamos o ponteiro header em 1. Como o tipo do ponteiro \u00e9 <code>Header*<\/code>, o incremento ser\u00e1, na verdade, o n\u00famero de bytes da struct <code>Header<\/code>, n\u00e3o um byte apenas.  Por isso, o tipo do ponteiro incrementado \u00e9 muito relevante na <a href=\"https:\/\/www.ime.usp.br\/~pf\/algoritmos\/aulas\/pont.html#array\">aritm\u00e9tica de ponteiros<\/a>.<\/p>\n\n\n\n<p>Agora que nossos blocos de mem\u00f3ria possuem metadados no in\u00edcio, \u00e9 preciso levar isso em conta na hora de desalocar.  <code>free()<\/code> recebe um ponteiro n\u00e3o para o come\u00e7o do bloco, mas para a mem\u00f3ria disponibilizada ao usu\u00e1rio. Logo, precisamos encontrar o come\u00e7o do bloco a partir do ponteiro que o usu\u00e1rio passou. Nada que uma pequena aritm\u00e9tica de ponteiros n\u00e3o resolva:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void abfree(void *ptr) {\n  Header *header = (Header*) ptr - 1;<\/pre>\n\n\n\n<p>Se <code>header<\/code> aponta para o \u00faltimo bloco alocado, o bloco anterior passar\u00e1 a ser o \u00faltimo. Neste caso, podemos retornar mem\u00f3ria do heap para o sistema operacional atrav\u00e9s de <code>brk()<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">  if (header == last) {<br>    last = header-&gt;previous;<br>    brk(header);<br>  }<\/pre>\n\n\n\n<p>Eis a nova vers\u00e3o de nossas fun\u00e7\u00f5es <code>malloc()<\/code> e <code>free()<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">typedef struct Header {\n   struct Header *previous;\n } Header;\n\n Header *last = NULL;\n\n void *abmalloc(size_t size) {\n   Header *header = sbrk(sizeof(Header) + size);\n   header-&gt;previous = last;\n   last = header;\n   return header + 1;\n }\n\n void abfree(void *ptr) {\n   Header *header = (Header*) ptr - 1;\n   if (header == last) {\n     last = header-&gt;previous;\n     brk(header);\n   }\n }<\/pre>\n\n\n\n<p><code>abmalloc()<\/code> e a<code>bfree()<\/code> podem ser ligeiramente mais econ\u00f4micos em mem\u00f3ria agora, mas n\u00e3o muito. Raramente a mem\u00f3ria alocada dinamicamente se comporta com uma pilha, onde o bloco mais velho \u00e9 sempre desalocado primeiro. No <a href=\"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-reutilizando-blocos-de-memoria\/\">pr\u00f3ximo post<\/a>, veremos como utilizar a mem\u00f3ria de blocos mais antigos que n\u00e3o est\u00e3o mais em uso.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Este post faz parte de uma s\u00e9rie sobre como implementar as fun\u00e7\u00f5es malloc() e free(). Anteriormente, fizemos uma implementa\u00e7\u00e3o s\u00e3o simpl\u00f3ria que praticamente n\u00e3o libera mem\u00f3ria nenhuma: um ponteiro aponta para o \u00faltimo bloco alocado, o que permite que abfree() o desaloque, mas somente ele. Uma op\u00e7\u00e3o melhor \u00e9 fazer o \u00faltimo bloco apontar para [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_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}},"categories":[29,179,24,10],"tags":[172,79,173,180,171,96,170,164],"class_list":["post-609","post","type-post","status-publish","format-standard","hentry","category-c","category-libc","category-linguagens-de-programacao","category-linux","tag-alocacao-de-memoria","tag-c","tag-crafting-interpreters","tag-desenvolvimento-de-software","tag-gerenciamento-de-memoria","tag-linguagens-de-programacao","tag-malloc","tag-programacao"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p23QLV-9P","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/609","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/comments?post=609"}],"version-history":[{"count":5,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/609\/revisions"}],"predecessor-version":[{"id":702,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/609\/revisions\/702"}],"wp:attachment":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/media?parent=609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/categories?post=609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/tags?post=609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}