<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vinicius Gabriel</title>
    <description>The latest articles on DEV Community by Vinicius Gabriel (@viniciusgabrielfo).</description>
    <link>https://dev.to/viniciusgabrielfo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F644876%2F55a5cc52-635b-43ff-b6ba-4f514fca862e.jpeg</url>
      <title>DEV Community: Vinicius Gabriel</title>
      <link>https://dev.to/viniciusgabrielfo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/viniciusgabrielfo"/>
    <language>en</language>
    <item>
      <title>Otimizando tamanho em memória de Structs em Golang</title>
      <dc:creator>Vinicius Gabriel</dc:creator>
      <pubDate>Mon, 22 May 2023 01:57:04 +0000</pubDate>
      <link>https://dev.to/viniciusgabrielfo/otimizando-tamanho-em-memoria-de-structs-em-golang-5b39</link>
      <guid>https://dev.to/viniciusgabrielfo/otimizando-tamanho-em-memoria-de-structs-em-golang-5b39</guid>
      <description>&lt;p&gt;Quando trabalhamos com Go, é muito comum utilizarmos a estrutura &lt;em&gt;Struct&lt;/em&gt; para agrupar vários campos com diferentes tipos primitivos de dados, mas como será que essa estrutura é armazenada em memória e existe alguma maneira de otimizar esse espaço ocupado em memória?&lt;/p&gt;

&lt;p&gt;Com esse questionamento acabei me deparando com dois conceitos que antes eu não conhecia, chamados de &lt;strong&gt;&lt;em&gt;Data Alignment&lt;/em&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;em&gt;Padding&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Para podermos entender os conceitos, é importante primeiro termos conhecimento de &lt;strong&gt;quanto cada tipo primitivo de dado ocupa em memória&lt;/strong&gt;, não vou me extender muito nesse assunto em específico, mas segue um breve resumo dos tipos primitivos e seus respectivos tamanhos em bytes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tipos primitivos em Go e seus respectivos tamanhos em bytes:

* string - 16 bytes
* int32 - 4 bytes
* int64 - 8 bytes
* int - depende da arquitetura do Sistema Operacional(32 bits - 4 bytes ou 64 bits - 8 bytes)
* uint - mesmas regras aplicados ao tipo int e respectivamente int32 e int64
* float32 - 4 bytes
* float64 - 8 bytes
* bool - 1 byte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Caso queira avaliar mais profundamente os tipos primitivos e seus tamanhos em Go você pode consultar &lt;a href="https://golang.org/src/go/types/sizes.go"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Em primeiro caso, para entendermos a ideia do &lt;em&gt;Padding&lt;/em&gt;, vamos trabalhar com essa struct:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type StructA struct {
    i32 int32
    s   string
    b   bool
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nós sabemos que um &lt;em&gt;int32&lt;/em&gt; ocupa 4 bytes, uma &lt;em&gt;string&lt;/em&gt; ocupa 16 bytes e um &lt;em&gt;bool&lt;/em&gt; ocupa 1 byte certo? Então em teoria o tamanho em memória da struct deveria ser exatamente a soma em bytes de todos os campos que ela contém, no caso da nossa &lt;em&gt;StructA&lt;/em&gt; deveria ser 21 bytes certo?&lt;/p&gt;

&lt;p&gt;Bom, podemos validar esse tamanho com a função &lt;a href="https://golang.org/pkg/unsafe/"&gt;&lt;strong&gt;&lt;u&gt;Sizeof() do pacote unsafe&lt;/u&gt;&lt;/strong&gt;&lt;/a&gt; que retorna o tamanho em bytes alocado para a estrutura passada na função dessa maneira:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "unsafe"
)

type StructA struct {
    i32 int32  // 4 bytes
    s   string // 16 bytes
    b   bool   // 1 bytes
}

func main() {
    a := StructA{}
    fmt.Println("Tamanho da StructA: ", unsafe.Sizeof(a))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O retorno que imaginamos seria 21 bytes certo? Mas o retorno desse script é:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tamanho da StructA: 32
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;E agora vem o ponto de dúvida, &lt;strong&gt;por que exatamente essa struct ocupa 32 bytes se a soma de todos os campos é 21 bytes? É aí que entra o &lt;em&gt;Data Alignment&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Para entermos melhor o conceito, é importante que saibamos de maneira abstrata como a memória é organizada em nossa máquina. A estrutura de memória é armazenada em células, seguindo uma estrutura parecida com essa:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x00 |  dados  |   
0x01 |   ...   |
0x02 |   ...   |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cada célula de memória, armazena um tamanho específico de bits, que depende da arquitetura do nosso sistema operacional (x32 ou x64), ou seja, 4 bytes para sistemas x32 e 8 bytes para sistemas x64&lt;/strong&gt;, podemos imaginar cada celula dessa maneira, tomando como premissa um SO x64:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x00 | byte | byte | byte | byte | byte | byte | byte | byte |  
0x01 |   ...   |
0x02 |   ...   |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;O &lt;em&gt;Data Alignment&lt;/em&gt; estrutura cada variável que criamos em nosso programa, para sempre estar alinhado em somente uma célula de memória.&lt;/strong&gt; Por exemplo, quando temos uma variável do tipo int32 (4 bytes), ele trabalhar para que todos os 4 bytes estejam na mesma célula de memória, para evitar que o processador tenha que acessar mais de uma célular de memória para ler ou escrever o conteúdo da nossa variável. Portanto nossa StructA, está organizada dessa forma em memória:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x00 | i32Byte | i32Byte | i32Byte | i32Byte | - | - | - | - |  
0x01 | sByte | sByte| sByte| sByte| sByte | sByte | sByte | sByte |
0x02 | sByte | sByte| sByte| sByte| sByte | sByte | sByte | sByte |
0x03 | boolByte| - | - | - | - | - | - | - |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Se contarmos cada byte alinhado na estrutura de memória acima representado pelo “| |”, podemos contar no total 32 casas, ou seja, nossos 32 bytes retornados pela função &lt;em&gt;unsafe.SizeOf()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A estrutura vazia na célula de memória representada pelo “-”, é o que chamamos de &lt;strong&gt;&lt;em&gt;Padding&lt;/em&gt;&lt;/strong&gt;. &lt;strong&gt;Sua função é basicamente completar o espaço não usado naquela célula, para que a próxima estrutura possa começar em uma nova célula de memória.&lt;/strong&gt; Já que caso a alocação dos bytes da nossa variável string inciasse no final da célula &lt;em&gt;0x00&lt;/em&gt;, o processador acabaria tendo que acessar 3 células de memória invés de 2 para trabalhar no conteúdo dessa variável, já que a organização ficaria dessa forma:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x00 |i32Byte|i32Byte|i32Byte|i32Byte|sByte|sByte|sByte|sByte|  
0x01 | sByte | sByte| sByte| sByte| sByte | sByte | sByte | sByte |
0x02 | sByte | sByte| sByte | sByte | - | - | - | - |
0x03 | boolByte| - | - | - | - | - | - | - |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Bom, agora sabemos que o &lt;strong&gt;&lt;em&gt;Data Alignment&lt;/em&gt; é responsável por trabalhar o alinhamento dos bytes das nossas variáveis nas células de memória&lt;/strong&gt;, para que o &lt;strong&gt;processador execute o mínimo de instruções possíveis&lt;/strong&gt; para manipular um dado em memória e o &lt;strong&gt;&lt;em&gt;Padding&lt;/em&gt; é o responsável por “preencher” os espaços não usados em cada endereço&lt;/strong&gt;, fornecendo o apoio para o alinhamento mais eficiente em memória.&lt;/p&gt;

&lt;p&gt;Sabendo disso, como então podemos utilizar esse conhecimento para otimizar nossas structs? É extremamente simples, basta &lt;strong&gt;reordenar os campos para que sempre que possível dois tipos que somado seus tamanhos em bytes seja no máximo 8&lt;/strong&gt;, ou seja, podem ocupar interiamente o mesmo alocamento de 8 bytes na memória.&lt;/p&gt;

&lt;p&gt;Para exemplicar, vamos criar uma nova struct chamada &lt;em&gt;StructAOptimized&lt;/em&gt;, onde reordenaremos os campos de maneira mais eficiente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "unsafe"
)

type StructA struct {
    i32 int32  // 4 bytes
    s   string // 16 bytes
    b   bool   // 1 bytes
}

type StructAOptimized* struct {
    i32 int32  // 4 bytes
    b   bool   // 1 bytes
    s   string // 16 bytes
}

func main() {
    a := StructA{}
    aOptimized := StructAOptimized{}

    fmt.Println("Tamanho da StructA: ", unsafe.Sizeof(a))
    fmt.Println("Tamanho da StructA Otimizada: ", unsafe.Sizeof(aOptimized))
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;O retorno desse script será:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tamanho da StructA:  32
Tamanho da StructA Otimizada:  24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Percebam que a única mudança da StructA para a StructAOptimized foi que alteremos a ordem entre o campo booleano e o campo string, apenas com esse pequeno ajuste reduzimos o tamanho alocado da struct em memória em 8 bytes. Mas por que isso ocorre?&lt;/p&gt;

&lt;p&gt;O &lt;em&gt;Data Alignment&lt;/em&gt; realiza o alinhamento dos dados em memória de maneira sequencial, portanto quando temos a estrutura da StructAOptimized, nossas células de memória estarão alinhadas dessa forma:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0x00 | i32Byte | i32Byte | i32Byte | i32Byte | boolByte |-|-|-|  
0x01 | sByte | sByte| sByte| sByte| sByte | sByte | sByte | sByte |
0x02 | sByte | sByte| sByte| sByte| sByte | sByte | sByte | sByte |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Percebam que como nossa variável do tipo int32 ocupa somente 4 bytes, há ainda 4 bytes livres no mesmo espaço de alocamento. Quando a segunda variável a ser alocado é uma string, o &lt;em&gt;Data Alignment&lt;/em&gt; começa a alocar os bytes da nossa string em uma nova estrutura, afim de otimizar o trabalho do processador, já que nossa variável string não acabe inteiramente nos 4 bytes que sobraram.&lt;/p&gt;

&lt;p&gt;Agora, no caso da nossa StructAOptimized o segundo campo a ser alocado é um boolean, que necessita de 1 byte, como é possível alocar todos os seus bytes no espaço restante do endereço 0x00, ele não precisa criar uma nova estrutura de 8 bytes.&lt;/p&gt;

&lt;p&gt;Espero que esse conteúdo tenha sido útil pra você que leu até aqui. Lembrando que toda a exemplificação foi utilizando Go, mas o mesmo comportamento pode ser reproduzido em outras linguagens.&lt;/p&gt;

&lt;p&gt;Deixei um repositório no Github com os testes realizados na explicação e mais uma demonstração com outras duas structs, você pode acessa-lo aqui: &lt;a href="https://github.com/viniciusgabrielfo/go-struct-optimization-test"&gt;https://github.com/viniciusgabrielfo/go-struct-optimization-test&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/38875369/what-is-data-alignment-why-and-when-should-i-be-worried-when-typecasting-pointe"&gt;https://stackoverflow.com/questions/38875369/what-is-data-alignment-why-and-when-should-i-be-worried-when-typecasting-pointe&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/"&gt;https://www.geeksforgeeks.org/structure-member-alignment-padding-and-data-packing/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>coding</category>
      <category>learning</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
