Propriedades rápidas e lentas no V8: Entendendo o armazenamento de objetos

A resposta envolve a implementação interna do motor V8, especialmente os conceitos de propriedades indexadas por arrays, propriedades nomeadas, propriedades in-object, classes ocultas e arrays de descritores.

Exemplo prático

Considere este trecho de código:

function testV8() {
  this[100] = 'test-100'
  this[1] = 'test-1'
  this["D"] = 'foo-D'
  this["B"] = 'foo-B'
  this[50] = 'test-50'
  this[9] = 'test-9'
  this[8] = 'test-8'
  this[3] = 'test-3'
  this[5] = 'test-5'
  this["4"] = 'test-4'
  this["A"] = 'foo-A'
  this["C"] = 'foo-C'
  this[4.5] = "foo-4.5"
}

const testObj = new testV8()

for (const key in testObj) {
  console.log(`key:${key}, value:${testObj[key]}`)
}

O resultado da execução mostra que a ordem das chaves é consistente entre as execuções, não havendo aleatoriedade. A análise revela duas regras importantes:

  • Chaves numéricas são listadas em ordem crescente.
  • Chaves não numéricas seguem a ordem de definição.

Tipos de propriedades no V8

No V8, existem dois tipos principais de armazenamento para propriedades:

  1. Propriedades indexadas por arrays: Armazenadas em uma estrutura linear com base em índices numéricos.
  2. Propriedades nomeadas: Armazenadas em outra estrutura linear com base em nomes de chave.

Cada tipo é mantido separadamente em estruturas distintas chamadsa properties e elements. No entanto, quando há menos de 10 propriedades nomeadas, estas são armazenadas diretamente no objeto, conhecidas como propriedades in-object, evitando uma etapa extra de acesso.

Snapshot no Chrome DevTools

Para inspecionar o comportamento real, utilize o DevTools do Chrome:

  1. Acesse a aba Memory.
  2. Clique em Take snapshot.
  3. Filtre pelo nome da função testV8.

Isso permite observar como as propriedades são realmente armazenadas.

Propriedades in-object vs. normais

Quando o número de propriedades nomeadas ultrapassa dez, elas são movidas para a estrutura properties. Essas são chamadas de propriedades normais e exigem uma etapa adicional para acesso.

Veja um exemplo:

function Foo(properties, elements) {
  // Adiciona propriedades indexadas
  for (let i = 0; i < elements; i++) {
    this[i] = `element${i}`
  }

  // Adiciona propriedades nomeadas
  for (let i = 0; i < properties; i++) {
    const prop = `property${i}`
    this[prop] = prop
  }
}
const foo = new Foo(12, 12)

Classes Ocultas (Hidden Classes)

Em linguagens estáticas, o layout de objetos é fixo após a criação. Em JavaScript, isso não ocorre, então o V8 usa classes ocultas para otimizar o acesso às propriedades.

Cada objeto possui uma classe oculta que contém metadados sobre suas propriedades. Quando uma propriedade é adicionada ou removida, uma nova classe oculta é criada e vinculada à anterior via ponteiro back_pointer.

Estrutura de uma Classe Oculta

Uma classe oculta contém:

  • Informações sobre o número de propriedades nomeadas.
  • Ponteiro para um array de descritores.

Os arrays de descritores guardam informações como nomes e localizações das propriedades nomeadas. Propriedades indexadas por array não são incluídas aqui.

Árvore de transição

Quando novas propriedades são adicionadas, o V8 cria novas classes ocultas e conecta-as formando uma árvore de transição, permitindo identificar objetos com estruturas semelhantes.

Propriedades rápidas e lentas

Propriedades armazenadas em estruturas lineares são chamadas de rápidas, pois permitem acesso direto com complexidade O(1). Por outro lado, quando há muitas propriedades, o V8 pode optar por usar uma estrutura de dicionário (dictionary), resultando em propriedades lentas.

Essas propriedades lentas não utilizam o array de descritores e armazenam seus dados em uma estrutura de dicionário interna, evitando atualizações na classe oculta, mas reduzindo a eficiência de cache inline.

Resumo

  • Propriedades indexadas são armazenadas em estruturas lineares.
  • Propriedades nomeadas até dez são armazenadas diretamente no objeto.
  • Classes ocultas ajudam a manter o desempenho ao rastrear mudanças nas propriedades.
  • Propriedades rápidas oferecem acesso rápido, enquanto propriedades lentas usam dicionários.

Tags: V8 javascript engine performance properties

Publicado em 9-6 03:47