stamatios
← Voltar ao feed
Mochila cheia se transforma em carteira fina com os mesmos cartões, Zod 4.5 reduz memória de schemas com memoização
Dev & Engenharia

Zod 4.5 corta uso de memória de schemas em até 10x com memoização

resumo de ~3 min

O problema: métodos auto-bound estouram a memória

O Zod 4.5 introduz um padrão chamado "method memoization" que reduz drasticamente o consumo de memória dos schemas. Em versões anteriores, todos os métodos dos schemas eram automaticamente vinculados (auto-bound), ou seja, não dependiam da semântica implícita de this. Isso permite códigos como desestruturar parse diretamente de z.string() e chamá-lo isoladamente sem quebrar.

O custo dessa conveniência era que cada método se tornava uma closure vinculada ocupando espaço na memória, impedindo que múltiplas instâncias de uma classe compartilhassem métodos via herança de protótipo. O resultado concreto: em Zod 4.4, um simples z.string() retinha 7,5 kb de heap por instância; no 4.5, apenas 784 bytes - uma redução de 9,8x.

A solução: memoização via getters que se auto-substituem

A correção funciona assim: as classes do Zod definem seus métodos como getters em um protótipo padrão. Na primeira vez que um método é acessado, o getter retorna a implementação vinculada à instância e a atribui como own property nela, memoizando-a permanentemente. Acessos seguintes evitam o overhead do getter e resolvem direto pela own property.

O ponto-chave é que um método nunca usado (e a maioria não é) nunca é materializado nem armazenado na instância. O autor descreve o padrão como uma variante mais sofisticada de um "self-overwriting getter" que já havia descrito antes.

Como o V8 agrava o problema

Um detalhe da alocação de memória do V8 piorava o cenário antigo:

  • Com menos de 13 own properties, o V8 usa um backing store compacto de 128 bytes;
  • Com 13 ou mais, ele salta para 848 bytes;
  • Com 21 ou mais, vai a 1.616 bytes.

Um schema de string no Zod 4.4.3 carregava 49 own properties (40 métodos e 9 propriedades), de modo que toda instância recebia o backing store de 1.616 bytes. No novo sistema, restam apenas seis propriedades eager: _zod, def, type, format, minLength e maxLength; todo o resto fica no protótipo memoizante (86 entradas no protótipo de z.string()).

Resultados medidos

Os ganhos variam conforme o tipo de schema: z.string() cai 9,8x (7,5 kb para 784 b), z.number() 6,4x, z.string().pipe(...) 9,6x, z.string().transform(...) 8,5x, z.string().optional() 8,4x e z.object({...}) com 10 chaves cai de 82 kb para 11 kb (7,5x). O menor ganho listado é z.object({}), com 2x. Medidas também cobrem zod/mini, como z.string() caindo de 2,5 kb para 577 b.

Os números vêm do benchmark packages/bench/memory/schema-footprint.ts do repositório, e o autor adverte que bytes retidos são difíceis de medir. A recomendação final é atualizar para o Zod 4.5 via npm upgrade zod@latest.