goroutine leaks no go 1.26

Detectando goroutine leaks no Go 1.26

Se você já trabalhou com Go em produção, provavelmente já enfrentou aquele cenário: goroutines que ficam presas para sempre, consumindo memória sem nunca terminar. O Go 1.26 trouxe uma ferramenta experimental que ataca esse problema direto na raiz: o goroutine leak profile.

O que são goroutine leaks?

Uma goroutine leak acontece quando uma goroutine fica bloqueada permanentemente — esperando em um channel, mutex ou condition variable que nunca vai ser desbloqueado. Na prática, é memória e recursos que ficam presos sem possibilidade de liberação.

O cenário mais clássico: você cria uma goroutine que escreve em um channel sem buffer, mas a função que deveria ler esse channel retorna antes por conta de um erro. A goroutine fica ali, bloqueada para sempre.

Leia mais »

Entendendo o Green Tea GC do Go 1.26

Go 1.26 trouxe uma das maiores mudanças no runtime dos últimos anos: o Green Tea garbage collector agora vem habilitado por padrão. Nesse post, vamos entender o que mudou, por que isso importa e o que esperar na prática.

O que é o Green Tea GC?

O Green Tea GC é uma reformulação do garbage collector do Go. Ele mantém a mesma abordagem mark-sweep do GC anterior, mas muda fundamentalmente a forma como os objetos são rastreados e escaneados.

A diferença principal: em vez de operar objeto por objeto espalhado pelo heap, o Green Tea trabalha no nível de páginas de memória. Ele agrupa objetos em blocos contíguos de 8 KiB chamados spans e escaneia vários objetos de uma vez dentro do mesmo span.

Leia mais »

Como Go 1.25 e 1.26 reduzem a pressão no GC

Nesse post, vamos entender uma das otimizações mais interessantes das últimas versões do Go: a capacidade do compilador de alocar slices na stack em mais cenários — sem você precisar mudar uma linha de código.

O problema: heap allocation e o GC

Em Go, cada variável precisa ser alocada em algum lugar: na stack (pilha) ou na heap. A stack é rápida — alocar e liberar memória lá é praticamente gratuito. Já a heap é gerenciada pelo garbage collector, o que tem um custo: quanto mais você aloca no heap, mais trabalho o GC tem para fazer.

O compilador do Go usa uma técnica chamada escape analysis para decidir onde cada variável vai parar. Se ele consegue provar que uma variável não vai “escapar” do escopo da função, ele a coloca na stack. Caso contrário, ela vai para o heap.

O problema é que essa análise é conservadora: em muitos casos práticos, como acumular elementos em um slice dentro de um loop, o compilador não tinha certeza se o slice ia escapar ou não e alocava no heap por precaução.

Leia mais »

Como comparar valores em Go

Comparar valores é uma das operações mais comuns em qualquer linguagem de programação, e em Go não é diferente. Porém, a simplicidade da linguagem esconde algumas nuances importantes sobre como certos tipos podem ou não ser comparados diretamente.

Neste post, exploraremos os operadores de comparação em Go, suas limitações e alternativas.

Operadores de Comparação

De modo geral, Go oferece dois operadores para comparação direta de valores:

  • ==: Verifica se os valores dos dois operandos são iguais.
  • !=: Verifica se os valores dos dois operandos são diferentes.

Esses operadores funcionam para os tipos chamados de “comparáveis”, como por exemplo o boolean, int, float, tipos complexos, string, channels, arrays, structs e ponteiros.

Para os tipos numéricos (int, float e tipos complexos) também podemos utilizar >, <, <= e >=.

Leia mais »

Por que evitar o package Reflect

O package reflect no Go é uma ferramenta poderosa que permite inspecionar e manipular tipos e valores em runtime. No entanto, como diria o tio Ben, “com grandes poderes vêm grandes responsabilidades”.

Embora possa parecer atraente em certos cenários, o uso excessivo ou inadequado do reflect pode introduzir problemas significativos no seu código, como dificuldades de manutenção, bugs difíceis de depurar e perda de performance.

Neste post, exploraremos o que é o package reflect, exemplos de sua utilização, onde ele é amplamente empregado e, mais importante, porque você deve evitá-lo quando possível.

O que é o package Reflect

O package reflect faz parte da biblioteca padrão do Go e oferece funcionalidades para inspecionar tipos e valores em runtime, ou seja, em tempo de execução.

Leia mais »

Dicas para escrever bons benchmarks

Escrever benchmarks em Go é uma prática essencial para desenvolvedores que buscam otimizar a performance de suas aplicações.

Um benchmark bem elaborado pode revelar gargalos e oportunidades de otimização que, de outra forma, poderiam passar despercebidos.

No entanto, existem armadilhas comuns que podem distorcer os resultados dos benchmarks, levando a conclusões incorretas.

Neste post, exploraremos os principais cuidados que devem ser tomados ao escrever benchmarks em Go, com exemplos de código que ilustram boas e más práticas.

Importância de escrever Benchmarks

Benchmarking é uma técnica que permite medir a eficiência de determinadas partes do código, como funções ou métodos, em termos de tempo de execução.

Ao escrever benchmarks, você pode identificar quais partes do código precisam ser otimizadas e quais já estão suficientemente rápidas. No contexto de desenvolvimento de software, benchmarks são fundamentais para garantir que mudanças no código não degradem a performance.

Leia mais »

Diferenças entre structs e classes

No Go, uma struct é um tipo de dado fundamental que agrupa “variáveis” (atributos) sob um único nome, similar a como uma classe agrupa propriedades e métodos em linguagens orientadas a objetos como Java ou C#. No entanto, existem diferenças significativas tanto na sintaxe quanto nos conceitos e funcionalidades oferecidos por structs em Go quando comparada com classes em outras linguagens.

Estrutura e Sintaxe

Struct

Em Go, uma struct é definida usando a palavra-chave struct. A definição de uma struct envolve apenas a declaração de atributos.

type Pessoa struct {
	Nome  string
	Idade int
}
Leia mais »

Otimização automatizada com PGO

A otimização de desempenho é uma preocupação constante no desenvolvimento de software, e a linguagem Go não é uma exceção. Uma técnica que tem ganhado bastante atenção nesse contexto é a Profile-Guided Optimization (PGO). Neste post, vamos explorar o que é PGO, sua história na linguagem Go, e como você pode utilizar essa técnica tanto em aplicações de linha de comando (CLI) quanto em APIs.

O que é PGO?

PGO é uma técnica de otimização que utiliza dados de execução de uma aplicação para guiar o processo de compilação. Ao contrário da otimização tradicional, onde o compilador faz suposições gerais, o PGO permite ao compilador otimizar o código com base em dados reais de uso, levando a um desempenho significativamente melhorado.

Leia mais »

Como escalar horizontalmente uma aplicação no Kubernetes

Se você já se deparou com gargalos de performance ou custos exorbitantes na sua jornada com Kubernetes, prepare-se para conhecer seu novo melhor amigo: o Horizontal Pod Autoscaler (HPA). Neste post, vamos mergulhar no universo do HPA, desvendando seus segredos e te equipando com o conhecimento necessário para otimizar seus clusters.

O que é o HPA?

A função básica do HPA é monitorar sua aplicação em tempo real, e ajustar automaticamente o número de pods em ação para garantir a melhor experiência possível para seus usuários. Em outras palavras, esse recurso mágico do Kubernetes permite escalar horizontalmente seus workloads de forma inteligente e eficiente.

Leia mais »

Benchmark: ORM vs SQL puro

Finalmente tive tempo para sanar, com dados, uma das minhas e, imagino que de várias outras pessoas, maiores dúvidas quando se trata de Go e banco de dados. Qual a diferença, ao nível de consumo de recurso e performance, entre utilizar GORM vs escrever SQL na unha.

Para ficar mais fácil a leitura, separei o post em tópicos. Iniciarei explicando como fiz o setup, as funções comuns e realizei a execução dos benchmarks. Depois, separo o código do benchmark, assim como o resultado, em ações de CRUD.

Setup

Primeiramente, criei os packages entities, orm e std. Dentro do package entities, criei uma struct para ser utilizada em todos os benchmarks.

package entities

type Category struct {
    ID          int64  `gorm:"column:id;primaryKey"`
    Name        string `gorm:"column:name"`
    Description string `gorm:"column:description"`
}
Leia mais »