Este artigo apresenta o Memory Inspector lançado no Chrome 91. Ele permite inspecionar ArrayBuffer, TypedArray, DataView e Wasm Memory.
Introdução
Já quis entender os dados no ArrayBuffer? Antes do Memory Inspector, as DevTools permitiam apenas insights limitados sobre ArrayBuffers. A inspeção da visualização Escopo durante uma sessão de depuração era limitada a uma lista de valores únicos no buffer de matriz, o que dificultava a compreensão dos dados como um todo. Por exemplo, a visualização Escopo mostra o buffer como intervalos expansíveis de matrizes no exemplo abaixo:
A navegação para um determinado intervalo dentro do buffer era um ponto problemático, exigindo que o usuário rolasse a tela para baixo até chegar a esse índice. Mas, mesmo que a navegação até uma posição seja fácil, essa forma de inspecionar valores é complicada: é difícil dizer o que esses números significam. E se eles não forem interpretados como bytes únicos, mas, por exemplo, como números inteiros de 32 bits?
Como inspecionar valores usando o Memory Inspector
Com o Chrome 91, apresentamos o Memory Inspector, uma ferramenta para inspecionar buffers de matriz. Você já deve ter visto ferramentas de inspeção de memória para visualizar dados binários, que mostram o conteúdo binário em uma grade com os endereços e oferecem maneiras diferentes de interpretar os valores subjacentes. É isso que o Memory Inspector oferece. Com o Memory Inspector, agora é possível visualizar o conteúdo, navegar por ele e selecionar tipos para interpretar os valores disponíveis. Ele mostra os valores ASCII ao lado dos bytes e permite que o usuário selecione diferentes endianidades. Confira o Memory Inspector em ação abaixo:
Quer fazer um teste? Para saber como abrir o Memory Inspector e conferir seu buffer de matriz (ou TypedArray, DataView ou Wasm Memory) e mais informações sobre como usá-lo, acesse nossa documentação sobre o Memory Inspector. Teste estes exemplos (para JS, Wasm e C++).
Como projetar o Inspetor de memória
Nesta parte, vamos analisar como o Memory Inspector foi projetado usando Web Components e mostraremos uma das metas de design que tínhamos e como a implementamos. Se você quiser saber mais, confira nosso documento de design sobre o Memory Inspector.
Você pode ter visto nossa postagem no blog sobre Como migrar para os Web Components, em que Jack publicou nosso guia interno sobre como criar componentes de interface usando Web Components. A migração para os Web Components coincidiu com nosso trabalho no Memory Inspector. Por isso, decidimos testar o novo sistema. Confira abaixo um diagrama que mostra os componentes que criamos para criar o Memory Inspector (chamado internamente de Linear Memory Inspector):
O componente LinearMemoryInspector
é o pai que combina os subcomponentes que criam todos os elementos no Memory Inspector. Basicamente, ele usa um Uint8Array
e um address
, e, em cada mudança, ele propaga os dados para os filhos, o que aciona uma nova renderização. O LinearMemoryInspector
renderiza três subcomponentes:
LinearMemoryViewer
(mostrando os valores),LinearMemoryNavigator
(permitindo a navegação) eLinearMemoryValueInterpreter
(mostrando diferentes interpretações de tipo dos dados subjacentes).
O último é um componente pai, que renderiza o ValueInterpreterDisplay
(mostrando os valores) e o ValueInterpreterSettings
(selecionando quais tipos serão mostrados na tela).
Cada um dos componentes é projetado para representar apenas um pequeno componente da interface, de modo que os componentes possam ser reutilizados, se necessário. Sempre que novos dados são definidos em um componente, uma nova renderização é acionada, mostrando a mudança refletida nos dados definidos no componente. Confira abaixo um exemplo de fluxo de trabalho com nossos componentes, em que o usuário está alterando o endereço na barra de endereço, o que aciona uma atualização ao definir os novos dados, neste caso, o endereço a ser visualizado:
O LinearMemoryInspector
se adiciona como um listener no LinearMemoryNavigator
. A função addressChanged
precisa ser acionada em um evento address-changed
. Assim que o usuário edita a entrada de endereço, o evento mencionado é enviado, de modo que a função addressChanged
seja chamada. Agora, essa função salva o endereço internamente e atualiza os subcomponentes usando um setter data(address, ..)
. Os subcomponentes salvam o endereço internamente e renderizam as visualizações novamente, mostrando o conteúdo nesse endereço específico.
Objetivo de design: tornar o desempenho e o consumo de memória independentes do tamanho do buffer
Um aspecto que tínhamos em mente durante o design do Inspetor de memória era que o desempenho dele deveria ser independente do tamanho do buffer.
Como você viu na parte anterior, o componente LinearMemoryInspector
usa um UInt8Array
para renderizar os valores. Ao mesmo tempo, queríamos garantir que o Memory Inspector não precisasse manter todos os dados, já que ele mostra apenas uma parte deles. Por exemplo, a memória Wasm pode ter até 4 GB, e não queremos armazenar esse volume no Memory Inspector.
Para garantir que a velocidade e o consumo de memória do Memory Inspector sejam independentes do buffer real que mostramos, permitimos que o componente LinearMemoryInspector
mantenha apenas um subintervalo do buffer original.
Para que isso funcione, o LinearMemoryInspector
precisa primeiro receber mais dois argumentos: um memoryOffset
e um outerMemoryLength
. O memoryOffset
indica o deslocamento, em que o Uint8Array transmitido começa, e é necessário para renderizar os endereços de dados corretos. O outerMemoryLength
é o comprimento do buffer original e é necessário para entender qual intervalo podemos mostrar:
Com essas informações, podemos garantir que ainda podemos renderizar a mesma visualização de antes (o conteúdo em torno do address
), sem ter todos os dados no lugar. O que fazer se um endereço diferente for solicitado, que se enquadra em um intervalo diferente? Nesse caso, o LinearMemoryInspector
aciona um RequestMemoryEvent
, que atualiza o intervalo atual que é mantido. Confira um exemplo abaixo:
Neste exemplo, o usuário navega pela página de memória (o Memory Inspector está usando a paginação para mostrar blocos de dados), o que aciona um PageNavigationEvent
, que aciona um RequestMemoryEvent
.
Esse evento inicia a busca do novo intervalo, que é propagado para o componente LinearMemoryInspector
ao definir os dados. Como resultado, mostramos os dados recém-buscados.
Ah, e você sabia? É possível até inspecionar a memória no código Wasm e C/C++.
O Memory Inspector não está disponível apenas para ArrayBuffers
em JavaScript, mas também pode ser usado para inspecionar a memória Wasm e a memória apontada por referências/ponteiros C/C++ (usando nossa extensão DWARF. Consulte Como depurar o WebAssembly com ferramentas modernas. Uma pequena perspectiva do Memory Inspector em ação para depuração nativa de C++ na Web:
Conclusão
Este artigo apresentou o Memory Inspector e mostrou um pouco do design dele. Esperamos que o Memory Inspector ajude você a entender o que está acontecendo no ArrayBuffer :-). Se você tiver sugestões para melhorar, entre em contato e registre um bug.
Fazer o download dos canais de visualização
Use o Chrome Canary, Dev ou Beta como navegador de desenvolvimento padrão. Esses canais de visualização dão acesso aos recursos mais recentes do DevTools, permitem testar APIs de plataforma da Web de última geração e ajudam a encontrar problemas no seu site antes dos usuários.
Entre em contato com a equipe do Chrome DevTools
Use as opções a seguir para discutir os novos recursos, atualizações ou qualquer outra coisa relacionada ao DevTools.
- Envie feedback e solicitações de recursos para crbug.com.
- Informe um problema do DevTools usando o Mais opções > Ajuda > Informar um problema do DevTools no DevTools.
- Envie um tweet para @ChromeDevTools.
- Deixe comentários nos vídeos Novidades do DevTools no YouTube ou Dicas do DevTools no YouTube.