{"id":623,"date":"2025-03-17T11:45:00","date_gmt":"2025-03-17T14:45:00","guid":{"rendered":"https:\/\/suspensao.blog.br\/descrenca\/?p=623"},"modified":"2025-03-23T23:16:12","modified_gmt":"2025-03-24T02:16:12","slug":"implementando-malloc-e-free-alinhamento-de-memoria","status":"publish","type":"post","link":"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-alinhamento-de-memoria\/","title":{"rendered":"Implementando malloc() e free() \u2014 alinhamento de mem\u00f3ria"},"content":{"rendered":"\n<p>Nossa implementa\u00e7\u00e3o de <code>malloc()<\/code> e <code>free()<\/code> avan\u00e7ou bastante. No <a href=\"https:\/\/suspensao.blog.br\/descrenca\/implementando-malloc-e-free-juntando-blocos-pequenos\/\">\u00faltimo post<\/a>, vimos por exemplo como unificar blocos de mem\u00f3ria menores para evitar fragmenta\u00e7\u00e3o. Para evitar ainda mais problemas nessa linha, vamos resolver detalhe importante para performance que estamos negligenciando h\u00e1 um tempo: alinhamento de mem\u00f3ria.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">O que \u00e9 alinhamento de mem\u00f3ria?<\/h2>\n\n\n\n<p>Computadores modernos <a href=\"https:\/\/en.wikipedia.org\/wiki\/Data_structure_alignment\">leem blocos de mem\u00f3ria de tamanho fixo, correspondente \u00e0 palavra do processador<\/a>. Um processador de 32 bits, por exemplo, l\u00ea quatro bytes por vez, enquanto um de 64 bits l\u00ea oito. No entanto, essa leitura s\u00f3 ocorre a partir de um endere\u00e7o alinhado \u2014 ou seja, um processador de 32 bits s\u00f3 consegue ler seus quatro bytes se o endere\u00e7o na mem\u00f3ria for m\u00faltiplo de quatro.<\/p>\n\n\n\n<p>Se o endere\u00e7o n\u00e3o for m\u00faltiplo do tamanho da palavra, o processador precisar\u00e1 acessar a mem\u00f3ria duas vezes: primeiro para buscar a primeira parte da palavra e depois para a segunda. Isso se torna ainda pior se o alocador retornar ponteiros desalinhados, pois todos os n\u00f3s seguintes tamb\u00e9m estar\u00e3o desalinhados, dobrando a quantidade de acessos \u00e0 mem\u00f3ria no <em>heap<\/em>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Garantindo o alinhamento dos blocos alocados<\/h2>\n\n\n\n<p>Para evitar esse problema, \u00e9 preciso alocar um m\u00faltiplo do tamanho da palavra do processador. No entanto, determinar esse tamanho pode ser complicado. Uma solu\u00e7\u00e3o simples e eficaz para nosso caso \u00e9 adotar m\u00faltiplos de 8 bytes, j\u00e1 que o barramento mais comum atualmente \u00e9 de 64 bits. Assim, todos os endere\u00e7os de blocos alocados devem ser m\u00faltiplos de 8. Vamos, ent\u00e3o, definir uma constante para o tamanho do alinhamento:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">define _ABMALLOC_ALIGNMENT_SIZE 8<\/pre>\n\n\n\n<p>Na fun\u00e7\u00e3o <code>abmalloc()<\/code>, verificamos se o tamanho solicitado est\u00e1 alinhado, ou seja, se \u00e9 m\u00faltiplo de <code>_ABMALLOC_ALIGNMENT_SIZE<\/code>. Se j\u00e1 estiver alinhado, n\u00e3o precisamos fazer nada:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">void<\/span> *abmalloc(size_t size) {\n  <span class=\"hljs-keyword\">if<\/span> (size == <span class=\"hljs-number\">0<\/span>) {\n    <span class=\"hljs-keyword\">return<\/span> NULL;\n  }\n  size_t rest = size % _ABMALLOC_ALIGNMENT_SIZE;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Se o tamanho solicitado n\u00e3o estiver alinhado, precisamos aument\u00e1-lo. Primeiro, calculamos o resto da divis\u00e3o do tamanho solicitado por <code>_ABMALLOC_ALIGNMENT_SIZE<\/code> e subtra\u00edmos este valor do tamanho originalmente solicitado. Em seguida, adicionamos <code>_ABMALLOC_ALIGNMENT_SIZE<\/code>. Isso garante que o novo tamanho seja o menor m\u00faltiplo poss\u00edvel do alinhamento necess\u00e1rio.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">if (rest != 0) {\n  size = size - rest + _ABMALLOC_ALIGNMENT_SIZE;\n}<\/code><\/span><\/pre>\n\n\n<p>Pronto! Agora, <code>abmalloc()<\/code> sempre retorna endere\u00e7os alinhados.<\/p>\n\n\n\n<p>Uma d\u00favida e uma vantagem extra<\/p>\n\n\n\n<p>Um questionamento v\u00e1lido \u00e9: isto n\u00e3o vai resultar em desperd\u00edcio de mem\u00f3ria? Em plataformas com barramentos de 32 bits, por exemplo, isto pode nos levar a alocar 7 bytes n\u00e3o usados quando poder\u00edamos alocar apenas 3 bytes n\u00e3o usados. Aqui, assumimos que este n\u00e3o \u00e9 um problema, mas existe uma solu\u00e7\u00e3o relativamente simples: apenas altere o valor da constante para 4, por exemplo, e recompile nosso c\u00f3digo.<\/p>\n\n\n\n<p>Este ajuste traz outra vantagem: blocos muito pequenos deixam de ser alocados. Por exemplo, se algu\u00e9m pedir um bloco de apenas 1 byte, ele dificilmente seria reutilizado, j\u00e1 que raramente se precisa de um \u00fanico byte. (Idealmente, nunca se deve alocar blocos t\u00e3o pequenos, mas esta \u00e9 uma decis\u00e3o do usu\u00e1rio.) Com um tamanho m\u00ednimo de 8 bytes, esses blocos menores, quando liberados, ter\u00e3o mais chances de serem reaproveitados.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclus\u00e3o<\/h2>\n\n\n\n<p>Com isso, terminamos nossa experi\u00eancia. Esta n\u00e3o \u00e9 uma implementa\u00e7\u00e3o muito boa de <code>malloc()<\/code>. Para come\u00e7ar, n\u00e3o \u00e9 <em>thread-safe<\/em>. Al\u00e9m disso, implementa\u00e7\u00f5es modernas utilizam t\u00e9cnicas e heur\u00edsticas muito mais eficientes, como <em><a href=\"https:\/\/www.openeuler.org\/en\/blog\/wangshuo\/Glibc_Malloc_Source_Code_Analysis_(1).html\">binning<\/a><\/em>. H\u00e1 tamb\u00e9m avan\u00e7os bem interessantes em pesquisas, como <a href=\"https:\/\/dl.acm.org\/doi\/10.1145\/3314221.3314582\">Mesh<\/a>.<\/p>\n\n\n\n<p>Nosso objetivo foi apenas conhecer um pouco mais, com um pouco de pr\u00e1tica e um c\u00f3digo evoluindo aos poucos, como aloca\u00e7\u00e3o de mem\u00f3ria funciona. Diga nos coment\u00e1rios se voc\u00ea conseguiu ou n\u00e3o entender um pouco mais do tema! E caso queira explorar mais, voc\u00ea pode conferir o resultado final no <a href=\"https:\/\/github.com\/brandizzi\/abmalloc\">reposit\u00f3rio do GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nossa implementa\u00e7\u00e3o de malloc() e free() avan\u00e7ou bastante. No \u00faltimo post, vimos por exemplo como unificar blocos de mem\u00f3ria menores para evitar fragmenta\u00e7\u00e3o. Para evitar ainda mais problemas nessa linha, vamos resolver detalhe importante para performance que estamos negligenciando h\u00e1 um tempo: alinhamento de mem\u00f3ria. O que \u00e9 alinhamento de mem\u00f3ria? Computadores modernos leem blocos [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":695,"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":"\ud83d\ude80 Melhoramos nossa implementa\u00e7\u00e3o de malloc(), agora garantindo alinhamento de mem\u00f3ria para evitar desperd\u00edcio e melhorar a performance. Pequenos ajustes, grandes impactos! Quer entender como isso funciona e por que faz diferen\u00e7a? Confira no post \ud83d\udc47","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[29,179,10],"tags":[79,180,171,170],"class_list":["post-623","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c","category-libc","category-linux","tag-c","tag-desenvolvimento-de-software","tag-gerenciamento-de-memoria","tag-malloc"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/suspensao.blog.br\/descrenca\/wp-content\/uploads\/2025\/03\/A-Lada-Vesta-Sport-having-its-wheels-aligned.jpg?fit=1488%2C680&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p23QLV-a3","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/623","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=623"}],"version-history":[{"count":6,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/623\/revisions"}],"predecessor-version":[{"id":707,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/posts\/623\/revisions\/707"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/media\/695"}],"wp:attachment":[{"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/media?parent=623"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/categories?post=623"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/suspensao.blog.br\/descrenca\/wp-json\/wp\/v2\/tags?post=623"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}