Ruby sob o Capô: Como a Memória e o object_id Funcionam de Verdade
Como Arrays acessam elementos em O(1), por que object_id não é endereço de memória no Ruby moderno e o que mudou do Ruby 2.6 ao 4.0.
Se você já estudou estruturas de dados, provavelmente aprendeu que um Array oferece acesso por índice em O(1). Isso não significa acesso literalmente instantâneo: significa que o número de operações não cresce com o tamanho do array.
Mas como o Ruby encontra array[2]? Ele consulta o object_id? E esse ID revela o endereço real do objeto? No Ruby moderno, a resposta para as duas perguntas é não.
Como um Array encontra o elemento sem usar `object_id`
array = ["maçãs", "bananas", "pepinos"]
array[2] # => "pepinos"Na implementação CRuby, um Array mantém seus elementos em posições consecutivas de uma área de armazenamento. Cada posição contém um VALUE, a representação de uma referência ou de um valor imediato na API C do Ruby.
Arrays pequenos podem guardar seus elementos dentro da própria estrutura RArray. Arrays maiores normalmente usam uma área separada apontada por RArray. Em ambos os casos, depois de validar e normalizar o índice, o acesso interno equivale a ptr[indice].
De forma conceitual, o cálculo é: endereço da posição = endereço inicial + (índice × tamanho de VALUE). Como não há varredura dos elementos anteriores, o custo é O(1). O código-fonte atual do CRuby mostra isso em rb_ary_entry_internal: depois dos testes de limite, ele retorna ptr[offset].
O que `object_id` realmente garante
A documentação oficial define object_id como um identificador inteiro único entre os objetos ativos do processo. O mesmo objeto devolve o mesmo ID durante sua vida, e dois objetos ativos diferentes não compartilham esse ID.
primeira = +"ruby"
segunda = primeira
terceira = +"ruby"
primeira.object_id == segunda.object_id # => true
primeira.object_id == terceira.object_id # => false
primeira.equal?(segunda) # => true
primeira.equal?(terceira) # => falseEsse é um contrato de identidade, não de localização. A documentação não promete que os números sejam endereços, sequenciais, persistentes entre execuções ou adequados como identificadores de banco de dados.
De endereço de memória a identificador lógico
Até o Ruby 2.6
Para objetos alocados na heap, o CRuby codificava object_id a partir do ponteiro do objeto. Por isso, em versões antigas, certas transformações de bits pareciam revelar o endereço interno. Isso era detalhe de implementação, não uma garantia portátil da linguagem.
Ruby 2.7: GC Compaction muda o cenário
O Ruby 2.7 introduziu GC.compact. A compactação move objetos vivos entre slots da heap para reduzir fragmentação e melhorar o compartilhamento copy-on-write. Um ID derivado da localização não poderia mudar toda vez que o objeto fosse movido.
Nessa geração do CRuby, os objetos comuns passaram a receber IDs crescentes sob demanda, mantidos em estruturas internas que o Garbage Collector atualizava quando os objetos se moviam. Portanto, calcular object_id << 1 deixou de ser uma forma válida de recuperar o endereço.
Ruby 4.0: o ID passa a acompanhar os campos do objeto
No Ruby 4.0, lançado em dezembro de 2025, a implementação mudou novamente: o object_id de objetos comuns é armazenado junto aos campos do próprio objeto. A tabela inversa necessária para ObjectSpace._id2ref é construída apenas se esse recurso for usado. Isso reduz contenção e trabalho do GC.
Como a compactação preserva a identidade
objeto = Object.new
id_antes = objeto.object_id
GC.compact if GC.respond_to?(:compact)
id_depois = objeto.object_id
id_antes == id_depois # => trueGC.compact pode mover objetos na heap, mas todas as referências gerenciadas pelo Ruby são atualizadas. O object_id permanece estável porque identidade e localização são conceitos separados no Ruby moderno.
A exceção: valores imediatos
nil, true, false, Symbols, inteiros pequenos e alguns Floats são representados como valores imediatos. Em vez de apontarem para um objeto separado na heap, seus dados e marcações de tipo cabem no próprio VALUE.
42.object_id == 42.object_id # => true
:ruby.object_id == :ruby.object_id # => true
"ruby".object_id == "ruby".object_id # => falseA última expressão cria duas strings mutáveis distintas. Já valores imediatos representam o próprio valor, e literais de string congelados também podem ser reutilizados pelo interpretador.
Resumo prático
- ▸Array#[] acessa uma posição do armazenamento interno por índice; não procura elementos por object_id.
- ▸Acesso por índice é O(1), mas ainda envolve validação do índice e acesso à memória.
- ▸object_id identifica logicamente um objeto ativo; ele não expõe sua localização atual.
- ▸Não derive endereços com object_id << 1 em Ruby moderno.
- ▸Use equal? para testar identidade de forma expressiva; use object_id principalmente para diagnóstico.
- ▸Não persista object_id nem o trate como UUID, token de segurança ou chave de negócio.
Fontes
- ▸Ruby 3.4, garantias públicas de Object#object_id: https://docs.ruby-lang.org/en/3.4/Object.html
- ▸Ruby C API, implementação de rb_ary_entry_internal: https://docs.ruby-lang.org/capi/en/master/df/d7d/internal_2array_8h_source.html
- ▸Ruby C API, estrutura RArray: https://docs.ruby-lang.org/capi/en/master/dd/d8b/struct_r_array.html
- ▸Ruby 2.7.0, anúncio oficial do Compaction GC: https://www.ruby-lang.org/en/news/2019/12/25/ruby-2-7-0-released/
- ▸Ruby Feature #15626, projeto do GC.compact e efeitos sobre object_id: https://bugs.ruby-lang.org/issues/15626
- ▸Ruby 4.0.0, mudanças oficiais em object_id e id2ref: https://www.ruby-lang.org/en/news/2025/12/25/ruby-4-0-0-released/
- ▸Código-fonte do Ruby, object_id armazenado nos campos do objeto: https://github.com/ruby/ruby/commit/f48e45d1e9c4412d5f3ee49241d0b9359651ce7c
- ▸MIT OpenCourseWare, arrays contíguos e aritmética de ponteiros: https://ocw.mit.edu/courses/6-s096-effective-programming-in-c-and-c-january-iap-2014/3f8f2bc5d4ee804b3bce651a210a940f_MIT6_S096IAP14_Lecture2.pdf
- ▸Google for Developers, ArrayList e acesso em tempo constante (referência geral): https://developers.google.com/j2objc/javadoc/jre/reference/java/util/ArrayList
✓ EOF, Israel Santos
← voltar aos artigos