4 pontos por GN⁺ 2024-03-31 | 1 comentários | Compartilhar no WhatsApp

Introdução ao RCU

  • O sistema operacional é, no dia a dia, um dos programas mais sensíveis a desempenho.
  • Um sistema operacional sempre pode ser mais rápido, e desenvolvedores de kernel e drivers se dedicam à otimização de código.
  • Um sistema operacional exige concorrência em larga escala, escalonando processos e threads em espaço de usuário, além de ter suas próprias threads e tratadores de interrupção que interagem com o hardware.

Como o RCU funciona

  • Quando é preciso alterar atomicamente dados lidos com frequência, mas escritos raramente (por exemplo, dispositivos USB atualmente conectados), usa-se a estratégia RCU (Read, Copy, Update).
  • Lê-se os dados, faz-se uma cópia para modificá-los e então atualiza-se atomicamente o ponteiro para a nova versão.
  • Esse método é fácil de usar e não tem espera, mas pode causar vazamentos de memória.

Resolvendo o problema de vazamento de memória

  • Para evitar vazamentos de memória, em vez de excluir os dados antigos dentro da função de atualização, é possível adiar a exclusão até que não haja mais leitores acessando-os.
  • Assim, gerencia-se a memória com segurança fazendo o escritor esperar para excluir os dados enquanto os leitores ainda estão lendo.

Uso prático do RCU

  • O RCU é usado dezenas de milhares de vezes no Linux, além de aparecer na biblioteca C++ Folly, do Facebook, e no crossbeam-epoch de Rust.
  • O RCU é motivado por requisitos de desempenho e latência, oferecendo uma forma de gerenciamento de memória semelhante à coleta de lixo.

Equívocos sobre coleta de lixo

  • A noção comum de que coleta de lixo é mais lenta do que gerenciamento manual de memória desmorona rapidamente quando se observam os detalhes.
  • A função free() não é gratuita, e o alocador de memória precisa manter internamente bastante estado.
  • Coletores de lixo modernos oferecem otimizações como movimentação e coleta geracional, proporcionando alta vazão e bom desempenho de cache.

A ilusão de controle

  • Às vezes, desenvolvedores querem construir sistemas de tempo real, mas na prática não têm controle perfeito sobre o gerenciamento de memória.
  • O sistema operacional apenas tenta inferir a intenção do desenvolvedor em relação à alocação de memória, e às vezes um simples acesso a ponteiro pode se transformar em I/O de disco.

Conclusão

  • Nem todo software se beneficia de coleta de lixo, mas ela é uma ferramenta útil e não deveria mais ser temida, nem mesmo entre programadores de sistemas.

Opinião do GN⁺

  • O RCU é uma técnica eficaz para aumentar a concorrência mantendo a consistência dos dados em ambientes multithread. Isso é um elemento muito importante em computação de alto desempenho e sistemas de tempo real.
  • O exemplo do RCU, que quebra noções preconcebidas sobre coleta de lixo, oferece aos desenvolvedores uma nova perspectiva sobre gerenciamento de memória. Isso vale ainda mais na área de programação de sistemas, em que o gerenciamento de memória é especialmente importante.
  • Outros projetos que oferecem funcionalidades semelhantes ao RCU incluem o ConcurrentLinkedQueue do Java e o ConcurrentBag do .NET, que também fornecem estruturas de dados lock-free.
  • Ao adotar a tecnologia RCU, é preciso considerar os requisitos do sistema e os objetivos de desempenho, entendendo os benefícios obtidos com seu uso e também seus custos potenciais.
  • Este artigo pode ajudar desenvolvedores a compreender melhor gerenciamento de memória e concorrência, reconsiderar pressupostos existentes e explorar novas soluções.

1 comentários

 
GN⁺ 2024-03-31
Comentários do Hacker News
  • Sugestão para conferir as técnicas inovadoras de coleta de lixo paralela (GC) do MPL e do MaPLe

    • Receberam o prêmio de artigo de destaque na POPL 2024 e o prêmio ACM SIGPLAN 2023
    • As principais propostas são as seguintes:
      • disentanglement baseado em coleta de lixo paralela comprovadamente eficiente
      • controle automático de granularidade comprovadamente eficiente
  • É interessante usar RCU como motivação para coleta de lixo

    • Faz sentido transferir a responsabilidade de liberar memória do escritor para o último leitor
    • Para melhorar o desempenho, talvez valha considerar transferir a liberação de memória para um processo em lote dedicado, em vez de deixá-la com o leitor
  • Equívocos gerais sobre gerenciamento de memória

    • Acreditar que o programador sabe qual é o tempo de pausa ideal para gerenciar memória
    • Em jogos e programas de negociação de criptomoedas, o programador pode de fato saber qual é o tempo de pausa ideal
  • O caso de uso de RCU é convincente, mas a experiência com coleta de lixo em outras situações não é boa

    • Soa como uma defesa de que soluções personalizadas de gerenciamento de memória podem oferecer o melhor desempenho
    • Discussão sobre o equívoco de que chamar free() devolve memória ao SO
  • Ao usar coleta de lixo, novas alocações passam a ocorrer na RAM, e não no cache

    • Isso pode ter grande impacto no desempenho
    • É fornecido um exemplo de benchmark na linguagem Julia
  • Uma boa coleta de lixo por rastreamento supera há muito tempo o gerenciamento manual de memória em termos de throughput

    • Mais recentemente, a latência ficou em nível aceitável para a maioria das aplicações
    • O uso de memória é a principal consideração
  • Uma das coisas que combinam bem com coleta de lixo é async/await

    • No Rust, o uso de async/await combinado com gerenciamento de memória causa problemas
  • Depois da motivação com RCU, é um pouco surpreendente mudar para uma discussão sobre coleta de lixo em geral

  • Ao desenvolver software, consideram-se dois casos

    • Para caminhos críticos, usa-se um alocador personalizado; fora disso, coleta de lixo é conveniente
  • A transição de RCU para coleta de lixo por rastreamento em geral parece uma estratégia astuta

    • Gerenciamento manual de memória envolve mais do que simplesmente chamar malloc/free
  • É difícil para programadores de sistemas identificar quando algo pode ser coletado pelo garbage collector

  • As ferramentas de gerenciamento de ciclo de vida do Rust e do C++ ajudam a automatizar a liberação de memória, mas não simplificam a complexidade