Terminologia da memória
Os seguintes termos são utilizados na ferramenta Memória , que serve para investigar problemas de memória. Estes termos de memória são aplicáveis à análise de memória em geral, bem como às ferramentas de criação de perfis de memória para idiomas como Java ou .NET.
Para saber mais sobre como utilizar a ferramenta Memória, veja Gravar instantâneos de área dinâmica para dados com a ferramenta memória (tipo de criação de perfis "Heap snapshot").
O gráfico de memória
Pense na memória utilizada por uma página Web como um grafo: uma estrutura que contém nós que estão ligados entre si por arestas:
Os nós no gráfico de memória representam os objetos utilizados pela página, incluindo tipos primitivos, como números ou cadeias javaScript, e objetos como matrizes associativas. Os nós e as arestas no gráfico de memória recebem as seguintes etiquetas:
Os nós (ou objetos) são rotulados com o nome da função de construtor que foi utilizada para os criar.
As arestas são etiquetadas com os nomes das propriedades.
Um nó no grafo pode conter memória de duas formas:
Diretamente; a memória é mantida pelo próprio objeto.
Implicitamente, ao guardar referências a outros objetos. Um objeto que contém referências a outros objetos impede que esses objetos sejam eliminados automaticamente pela libertação da memória (GC).
Memória de composição e área dinâmica para dados JavaScript
A área dinâmica para dados javaScript é uma região de memória no processo do browser onde vivem todos os objetos JavaScript e WebAssembly. A área dinâmica para dados JavaScript também é denominada memória V8 (depois do motor JavaScript V8 que alimenta o Microsoft Edge).
A área dinâmica para dados JavaScript faz parte da memória do compositor. A memória do compositor é a memória utilizada pelo processo do browser onde a página Web é composta. A memória do compositor é composta pelo seguinte:
- Memória nativa, como a memória utilizada por objetos C++ que representam os nós DOM.
- Memória dinâmica para dados javaScript da página.
- Memória dinâmica para dados javaScript de todas as funções de trabalho dedicadas que são iniciadas pela página.
A ferramenta Memória mostra ambos:
- A memória V8.
- Os objetos alocados na memória nativa que são relevantes para a página Web composta.
Raízes de libertação da memória
As raízes de libertação da memória (raízes GC) são criadas pelo browser quando é feita uma referência a partir do código nativo do browser para um objeto JavaScript que está fora da máquina virtual V8. Estas referências são denominadas identificadores.
Existem muitas raízes de GC internas, a maioria das quais não são interessantes para programadores Web. Do ponto de vista da página Web, existem os seguintes tipos de raízes GC:
Janela objetos globais (um em cada iframe).
Por vezes, os objetos são retidos pelo contexto de depuração definido pela ferramenta Origens ou Consola , como ao avaliar uma expressão JavaScript na ferramenta Consola . Para remover estes objetos da ferramenta Memória, antes de gravar uma área dinâmica para dados snapshot, limpe a ferramenta Consola e desative os pontos de interrupção na ferramenta Origens.
O gráfico de memória começa com uma raiz GC, que pode ser o window
objeto do browser ou o Global
objeto de um módulo Node.js. Não controla a forma como o objeto raiz é recolhido pela memória:
Os nós que não estão acessíveis a partir da raiz podem ser recolhidos da memória.
Tamanhos e distâncias dos objetos
A ferramenta Memória apresenta as seguintes colunas de informações:
- A coluna Distância
- A coluna Tamanho raso
- A coluna Tamanho retido
Estas colunas estão descritas abaixo.
Distância
A distância de um objeto na área dinâmica para dados javaScript é o número de nós no caminho mais curto entre o objeto e a raiz GC. Quanto mais curta for a distância, maior é a probabilidade de este objeto desempenhar um papel importante na utilização da memória da página Web.
Tamanho raso
O tamanho raso é o tamanho da área dinâmica para dados JavaScript que é mantida diretamente por um objeto. O tamanho raso de um objeto é geralmente pequeno, porque um objeto JavaScript armazena frequentemente apenas a descrição do objeto, não os valores, na memória direta do objeto. A maioria dos objetos JavaScript armazena os respetivos valores num arquivo de apoio que está noutro local na área dinâmica para dados javaScript e expõe apenas um pequeno objeto de wrapper na parte da área dinâmica para dados JavaScript que pertence diretamente ao objeto.
No entanto, mesmo um pequeno objeto pode conter indiretamente uma grande quantidade de memória, impedindo que outros objetos sejam eliminados pelo processo de libertação da memória.
Os números na coluna Tamanho raso são o número de bytes.
Tamanho retido
O tamanho retido é o tamanho da memória que é implicitamente mantida por um objeto e que pode ser libertada assim que o objeto e outros retentores existentes forem eliminados juntamente com todos os objetos dependentes que foram tornados inacessíveis a partir das raízes GC.
Ou seja, o tamanho retido de um objeto é a quantidade de memória que seria recuperada se o objeto e todos os objetos dependentes fossem removidos do gráfico de memória.
O tamanho retido não pode ser menor do que o tamanho raso.
Quando um objeto é retido por vários nós, o tamanho do objeto aparece no tamanho retido do nó de retenção que tem o caminho mais curto para a raiz GC.
Os números na coluna Tamanho retido são o número de bytes.
Retentores
Os retentores de um objeto são os outros objetos que contêm referências ao objeto. A secção Retentores da ferramenta Memória mostra os objetos que contêm referências ao objeto selecionado na vista Resumo .
A secção Retentores da ferramenta Memória está ordenada por distância por predefinição, o que significa que os caminhos de retenção mais simples para um objeto são apresentados primeiro.
Qualquer objeto sem retentores pode ser eliminado pelo recoletor de lixo do browser, o que reduz a utilização da memória.
Detalhes da V8
Ao criar perfis de memória, é útil compreender por que motivo os instantâneos de área dinâmica para dados têm um certo aspeto. Esta secção descreve como alguns objetos são armazenados na memória pela máquina virtual JavaScript V8 (abreviada aqui como VM V8 ou apenas VM), o que pode ajudá-lo a analisar instantâneos de área dinâmica para dados na ferramenta Memória .
Primitivos de JavaScript
Em JavaScript, existem vários tipos primitivos, tais como:
- Números (como
3.14159
). - Booleanos (
true
oufalse
). - Cadeias (como
"Werner Heisenberg"
).
Os primitivos não podem referenciar outros valores e são sempre nós de folha (também denominados nós de terminação) no gráfico de memória.
Os números podem ser armazenados como:
Valores inteiros de 31 bits imediatos denominados números inteiros pequenos (SMIs).
Objetos de área dinâmica para dados, que são referidos como números de área dinâmica para dados. Os números de área dinâmica para dados são utilizados para armazenar valores que não se enquadram no formato de número inteiro pequeno (SMI), como valores do tipo
double
ou quando um valor precisa de ser encaixotado, como definir propriedades no mesmo.
As cadeias de carateres podem ser armazenadas em:
A área dinâmica para dados da VM.
Externamente na memória do compositor. É criado um objeto de wrapper e utilizado para aceder ao armazenamento externo onde, por exemplo, as origens de script e outros conteúdos recebidos da Web são armazenados, em vez de serem copiados para a área dinâmica para dados da VM.
Objetos JavaScript
A memória para novos objetos JavaScript é alocada a partir de uma área dinâmica para dados de JavaScript (ou área dinâmica para dados de VMs) dedicada. Estes objetos são geridos pelo recoletor de lixo da V8 VM e, por conseguinte, estes objetos permanecem vivos desde que exista, pelo menos, uma referência aos mesmos.
Outros objetos
Objetos nativos: qualquer coisa que não esteja armazenada na área dinâmica para dados JavaScript é denominada objeto nativo. Um objeto nativo, ao contrário de um objeto de área dinâmica para dados, não é gerido pelo recoletor de lixo V8 ao longo da sua duração e só pode ser acedido a partir de JavaScript através do respetivo objeto de wrapper JavaScript.
Cadeias concatenadas: as cadeias que são armazenadas e, em seguida, unidas, como resultado de uma concatenação de cadeias em JavaScript, são armazenadas como cadeias concatenadas no V8. A associação do conteúdo da cadeia ocorre apenas conforme necessário, como quando uma subcadeia de uma cadeia associada precisa de ser construída.
Por exemplo, se concatenar
a
eb
, obterá uma cadeia concatenada(a, b)
que representa o resultado da concatenação. Se, posteriormente, concatenarc
com esse resultado, obterá outra cadeia concatenada:((a, b), c)
.Matrizes: uma matriz é um objeto que tem chaves numéricas. As matrizes são utilizadas extensivamente na VM V8 para armazenar grandes quantidades de dados. Os conjuntos de pares chave-valor que são utilizados como dicionários são implementados como matrizes.
Um objeto JavaScript típico é armazenado como apenas um de dois tipos de matriz:
- Uma matriz para armazenar propriedades nomeadas.
- Uma matriz para armazenar elementos numéricos.
Quando existe um pequeno número de propriedades, as propriedades são armazenadas internamente no objeto JavaScript.
system/Map: um objeto que descreve o tipo de objeto que é e o esquema. Por exemplo, os objetos de sistema/mapa são utilizados para descrever hierarquias implícitas de objetos para acesso rápido a propriedades. Veja Propriedades rápidas no V8.
Observação
Partes desta página são modificações baseadas no trabalho criado e partilhado pela Google e utilizado de acordo com os termos descritos na Licença Internacional Creative Commons Attribution 4.0. A página original é encontrada aqui e é da autoria de Meggin Kearney.
Este trabalho é licenciado ao abrigo de uma Licença Internacional creative Commons Attribution 4.0.