O Memory Profiler é um componente do Android Profiler que o ajuda a identificar vazamentos de memória e churn de memória que podem levar à gagueira, congelamento e até mesmo falhas de aplicativos. Ele mostra um gráfico em tempo real do uso da memória do seu aplicativo e permite que você capture um depósito de lixo, force coletas de lixo e alocações de trackmemory.
Para abrir o Memory Profiler, siga estes passos:
- Click View > Tool Windows > Profiler (você também pode clicar em Profile na barra de ferramentas).
- Selecione o dispositivo e o processo do aplicativo que você deseja fazer o perfil a partir da barra de ferramentas do AndroidProfiler. Se você conectou um dispositivo via USB mas não o vê na lista, certifique-se de ter habilitado a depuração USB.
- Clique em qualquer lugar na linha de tempo MEMORY para abrir o Memory Profiler.
Alternativamente, você pode inspecionar a memória da sua aplicação a partir da linha de comando withdumpsys, e tambémee eventos GC em logcat.
Por que você deve fazer o perfil da sua memória da aplicação
Android fornece um ambiente de memória amanhecida – quando determina que sua aplicação não está mais usando alguns objetos, o coletor de lixo libera a memória não usada de volta para a pilha. Como o Android vai encontrar memória não utilizada está sendo constantemente melhorado, mas em algum momento em todas as versões do Android, o sistema deve pausar brevemente o seu código. Na maioria das vezes, as pausas são imperceptíveis. No entanto, se o seu aplicativo aloca memória mais rapidamente do que o sistema pode coletá-la, seu aplicativo pode ser atrasado enquanto o coletor libera memória suficiente para satisfazer suas alocações. O atraso pode fazer com que seu aplicativo salte os quadros e cause lentidão visível.
Even se seu aplicativo não exibir lentidão, se ele vazar memória, ele pode reter essa memória mesmo enquanto estiver em segundo plano. Este comportamento pode retardar o resto do desempenho da memória do sistema forçando eventos de coleta de lixo desnecessários. Eventualmente, o sistema é forçado a matar seu processo de aplicação para recuperar a memória. Então quando o usuário retornar ao seu aplicativo, ele deve reiniciar completamente.
Para ajudar a prevenir estes problemas, você deve usar o Memory Profiler para fazer o seguinte:
- Localize padrões indesejáveis de alocação de memória na linha de tempo que podem estar causando problemas de performance.
- Dump the Java heap to see which objects are using up memory at any giventime. Vários despejos de memória durante um longo período de tempo podem ajudar a identificar vazamentos de memória.
- Record memory allocations during normal and extreme user interaction toidentify exactly where your code is either allocating too many objects in ashort time or allocating objects that become leaked.
Para informações sobre práticas de programação que podem reduzir o uso de memória da sua aplicação, leia Gerenciar a memória da sua aplicação.
Visão geral do Memory Profiler
Quando você abre o Memory Profiler pela primeira vez, você verá uma linha de tempo detalhada do uso e acesso às ferramentas de memória do yourapp para forçar a coleta de lixo, capturar um heapdump e gravar alocações de memória.
Figure 1. O Profiler de Memória
Como indicado na figura 1, a visualização padrão do Profiler de Memória inclui o seguinte:
- Um botão para forçar um evento de coleta de lixo.
-
Um botão para capturar um depósito de lixo.
Nota: Um botão para gravar alocações de memória aparece à direita do botão de despejo da pilha somente quando conectado a um dispositivo rodando Android 7.1 (API nível 25) ou inferior.
- Um menu suspenso para especificar a freqüência com que o profiler captura alocações de memória. Selecionar a opção apropriada pode ajudá-lo a melhorar o desempenho do aplicativo enquanto faz o perfil.
- Buttons para aumentar ou diminuir o zoom da linha de tempo.
- Um botão para avançar para os dados da memória ao vivo.
- A linha de tempo do evento, que mostra os estados de atividade, eventos de entrada do usuário e eventos de rotação da tela.
- A linha de tempo de uso da memória, que inclui o seguinte:
- Um gráfico empilhado de quanta memória está sendo usada por cada categoria de memória, como indicado pelo eixo y à esquerda e a tecla de cor no topo.
- Uma linha tracejada indica o número de objetos alocados, como indicado pelo eixo y à direita.
- Um ícone para cada evento de coleta de lixo.
No entanto, se você estiver usando um dispositivo rodando Android 7.1 ou inferior, nem todos os dados de perfil são visíveis por padrão. Se você vir uma mensagem que diz, “Advancedprofiling is unavailable for the selected process,” você precisa ativar o perfil avançado para ver o seguinte:
- Event timeline
- Número de objetos alocados
- Agregar eventos de coleta de lixo
No Android 8.0 e superior, o perfil avançado está sempre habilitado para debuggableapps.
Como a memória é contada
Os números que você vê no topo do Memory Profiler (figura 2) são baseados em todas as páginas de memória privada que a sua aplicação cometeu, de acordo com o sistema Android. Esta contagem não inclui páginas partilhadas com o sistema ou outras aplicações.
Figure 2. A legenda da contagem da memória no topo do Memory Profiler
As categorias na contagem da memória são as seguintes:
- Java: Memória de objectos atribuídos a partir de Java ou código Kotlin.
-
Nativo: Memória de objetos alocados a partir de C ou C++ code.
Even se você não estiver usando C++ em sua aplicação, você pode ver alguma memória nativa usada aqui porque o framework Android usa memória nativa para lidar com várias tarefas em seu nome, como ao lidar com ativos de imagem e outros gráficos – mesmo que o código que você escreveu esteja em Java ou Kotlin.
-
Graphics: Memória usada para filas de buffer gráficos para exibir pixels na tela, incluindo superfícies GL, texturas GL, e assim por diante. (Note que isto é memória compartilhada com a CPU, não memória GPU dedicada.)
-
Stack: Memória usada tanto por pilhas nativas como Java na sua aplicação. Isto normalmente está relacionado com quantos threads sua aplicação está rodando.
-
Code: Memória que sua aplicação usa para código e recursos, tais como dex bytecode, código dex otimizado ou compilado, .so bibliotecas e fontes.
-
Outros: Memória usada pelo seu aplicativo que o sistema não tem certeza de como categorizar.
-
Alocado: O número de objectos Java/Kotlin atribuídos pela sua aplicação. Isso não conta os objetos alocados em C ou C++.
Quando conectado a um dispositivo rodando Android 7.1 e inferior, essa contagem de alocação começa somente no momento em que o Profiler de Memória é conectado à sua aplicação em execução. Portanto, quaisquer objetos alocados antes de você iniciar a criação do perfil não são contabilizados. No entanto, o Android 8.0 e superior inclui uma ferramenta de criação de perfis no dispositivo que mantém o controle de todas as alocações, então este número sempre representa o número total de objetos Java pendentes no seu aplicativo no Android 8.0 e superior.
Quando comparado com a contagem de memória da ferramenta anterior Android Monitor, o novoMemory Profiler grava sua memória de forma diferente, então pode parecer que a utilização da memória do usuário é agora maior. O Memory Profiler monitora algumas categorias extras que aumentam o total, mas se você só se importa com a memória heap Java, o número “Java” deve ser similar ao valor da ferramenta anterior. Embora o número Java provavelmente não corresponda exatamente ao que você viu no AndroidMonitor, o novo número contabiliza todas as páginas de memória física que foram alocadas para o heap Java da sua aplicação desde que foi bifurcado do Zygote. Então isso fornece uma representação precisa de quanta memória física sua aplicação está usando.
Veja alocações de memória
Alocações de memória mostram como cada objeto Java e referência JNI no yourmemory foi alocado. Especificamente, o Memory Profiler pode lhe mostrar o seguinte sobre alocações de objetos:
- Que tipos de objetos foram alocados e quanto espaço eles usam.
- O traço da pilha de cada alocação, incluindo em qual thread.
- Quando os objetos foram desalocados (apenas quando usando um dispositivo com Android 8.0 ou superior).
Se o seu dispositivo estiver rodando Android 8.0 ou superior, você pode visualizar suas alocações de objetos a qualquer momento da seguinte forma: Arraste na linha de tempo para selecionar a alocação para a qual você deseja ver as alocações (como mostrado no vídeo 1). Não há necessidade de iniciar uma sessão de gravação, porque o Android 8.0 ou superior inclui uma ferramenta de perfil anon-device que acompanha constantemente as alocações do seu aplicativo.
Video 1. Com o Android 8.0 e superior, selecione uma área de linha de tempo existente para visualizar alocações de objetos
Se o seu dispositivo estiver executando o Android 7.1 ou inferior, clique em Record memoryallocations na barra de ferramentas do Memory Profiler. Durante a gravação, oMemory Profiler rastreia todas as alocações que ocorrem no seu aplicativo. Quando terminar, clique em Stop recording(o mesmo botão; veja o vídeo 2) para ver as alocações.
Video 2. Com o Android 7.1 e inferior, você deve gravar alocações de memória de forma explícita
Depois de selecionar uma região da linha do tempo (ou quando você terminar uma gravação com um dispositivo rodando Android 7.1 ou inferior), a lista de alocação de objetos aparece abaixo da linha de tempo, agrupada por nome de classe e ordenada por sua contagem de pilha.
Para inspecionar o registro de alocação, siga estes passos:
- Navegue na lista para encontrar objetos que tenham contagens de pilha invulgarmente grandes e que possam ser vazados. Para ajudar a encontrar classes conhecidas, clique no cabeçalho da coluna de classes Namecolumn para ordenar em ordem alfabética. Depois clique no nome de uma classe. O painelInstance View aparece à direita, mostrando cada instância dessa classe, como mostrado na figura 3.
- Alternativamente, você pode localizar objetos rapidamente clicando em Filter,ou pressionando Control+F (Command+F no Mac), e digitando uma classe ou nome de pacote no campo de busca. Você também pode procurar pelo nome do método se você selecionarArrange by callstack no menu suspenso. Se você quiser usar expressões regulares, marque a caixa ao lado de Regex. Marque a caixa ao lado da caixaMatch se a sua consulta de pesquisa for sensível a maiúsculas e minúsculas.
- No painel de Vista de Instância, clique numa instância. A aba Call Stack aparece abaixo, mostrando onde essa instância foi alocada e em qual thread.
- Na aba Call Stack, clique com o botão direito em qualquer linha e escolhaJump to Source para abrir esse código no editor.
Figure 3. Detalhes sobre cada objeto alocado aparecem na Visão da Instância à direita
Você pode usar os dois menus acima da lista de objetos alocados para escolher qual pilha inspecionar e como organizar os dados.
No menu da esquerda, escolha qual pilha inspecionar:
- pilha padrão: Quando nenhuma pilha for especificada pelo sistema.
- pilha de imagens: A imagem de inicialização do sistema, contendo classes que são pré-carregadas durante o tempo de inicialização. As alocações aqui são garantidas para nunca mover ou ir embora.
- zygote heap: A copy-on-write heap onde um processo de aplicação é bifurcado no sistema Android.
- app heap: A pilha primária na qual a sua aplicação aloca memória.
- pilha de JNI: A pilha que mostra onde as referências da Interface Nativa Java (JNI) são alocadas e liberadas.
No menu à direita, escolha como organizar as alocações:
- Organizar por classe: Agrupa todas as alocações com base no nome da classe. Este é o padrão.
- Arranjar por pacote: Agrupa todas as alocações baseadas no nome do pacote.
- Arranjar por pilha de chamadas: Agrupa todas as alocações em sua pilha de chamadas correspondentes.
Melhorar o desempenho da aplicação durante a criação de perfis
Para melhorar o desempenho da aplicação durante a criação de perfis, as alocações de memória do profiler periodicamente por padrão. Ao testar em dispositivos rodando APIlevel 26 ou superior, você pode alterar esse comportamento usando a dropdown Allocation Tracking Tracking. As opções disponíveis são asfollows:
- Full: Captura todas as alocações de objetos na memória. Este é o comportamento padrão no Android Studio 3.2 e anteriores. Se você tem uma app que atribui muitos objetos, você pode observar slowdowns visíveis com você enquanto faz o perfil.
- Sampled: Amostras de alocações de objetos na memória em intervalos regulares. Esta é a opção padrão e tem menos impacto no desempenho da aplicação durante a criação de perfis. Os aplicativos que alocam muitos objetos em um curto espaço de tempo podem ainda exibir slowdowns visíveis.
- Off: Pára de rastrear a alocação de memória do seu aplicativo.
Ver referências globais JNI
Java Native Interface (JNI) é um framework que permite que o código Java e o nativecode chamem um ao outro.
As referências JNI são gerenciadas manualmente pelo código nativo, assim é possível que objetosJava usados pelo código nativo sejam mantidos vivos por muito tempo. Alguns objetos na pilha Java podem se tornar inalcançáveis se uma referência JNI for descartada sem primeiro ser explicitamente excluída. Também é possível esgotar o limite de referência global da JNI.
Para resolver tais problemas, use a vista de heap JNI no Memory Profiler para percorrer todas as referências globais da JNI e filtrá-las por tipos Java e callstacks nativos. Com estas informações, você pode encontrar quando e onde as referências globais JNI são criadas e excluídas.
Aquando seu aplicativo estiver rodando, selecione uma parte da linha do tempo que você quer inspecionar e selecione a pilha de JNI no menu suspenso acima da lista de classes.Você pode então inspecionar objetos no heap como você normalmente faria e clicar duas vezes em objetos na aba Allocation Call Stack para ver onde as referências JNI são alocadas e liberadas no seu código, como mostrado na figura 4.
Figure 4. Visualizando referências globais JNI
Para inspecionar alocações de memória para o código JNI do seu aplicativo, você deve implantar seu aplicativo para um dispositivo rodando Android 8.0 ou superior.
Para mais informações sobre JNI, veja dicas JNI.
Profiler de memória nativa
O Profiler de memória do Android Studio inclui um Profiler de memória nativa paraapps implantado em dispositivos físicos rodando Android 10; o suporte para Android 11devices está atualmente disponível na versão de pré-visualização do Android Studio 4.2.
O Profiler de memória nativa rastreia alocações/desalocações de objetos em código nativo por um período de tempo específico e fornece as seguintes informações:
- Alocações: Uma contagem de objetos alocados via
malloc()
ou o operadornew
durante o período de tempo selecionado. - Desalocações: Uma contagem de objetos alocados via
free()
ou o operadordelete
durante o período de tempo selecionado. - Tamanho das alocações: O tamanho agregado em bytes de todas as alocações durante o período de tempo selecionado.
- Tamanho das alocações: O tamanho agregado em bytes de todas as alocações liberadas durante o período selecionado.
- Contagem total: O valor na coluna Alocações menos o valor na coluna Desalocações.
- Tamanho restante: O valor na coluna Tamanho de Alocações menos o valor na coluna Tamanho de Desalocações.
Para iniciar uma gravação, clique em Gravar alocações nativas no topo da janelaMemory Profiler:
Quando estiver pronto para completar a gravação, clique em Parar gravação.
Por padrão, o Native Memory Profiler usa um tamanho de amostra de 32 bytes: Toda vez que 32 bytes de memória são alocados, um instantâneo da memória é tirado. Um tamanho de amostra menor resulta em instantâneos mais frequentes, produzindo dados mais precisos sobre o uso da memória. Um tamanho de amostra maior produz menos dados precisos, mas consumirá menos recursos no seu sistema e melhorará o desempenho durante a gravação.
Para alterar o tamanho da amostra do Profiler de Memória Nativa:
- Select Run > Edit Configurations.
- Seleccione o seu módulo de aplicação no painel esquerdo.
- Clique na aba Profiling, e digite o tamanho da amostra no campo chamadoNative memory sampling interval (bytes).
- Build e execute sua aplicação novamente.
Capture a heap dump
A heap dump mostra quais objetos em sua aplicação estão usando memória no momento em que você capturou a heap dump. Especialmente depois de uma sessão estendida do usuário, um dumpcan heap dump ajuda a identificar vazamentos de memória, mostrando objetos ainda na memória que você acredita que não devem mais estar lá.
Depois de capturar um heap dump, você pode ver o seguinte:
- Que tipos de objetos sua aplicação tem alocados, e quantos de cada um.
- Quanta memória cada objeto está usando.
- Onde referências a cada objeto estão sendo mantidas no seu código.
- A pilha de chamadas para onde um objeto foi alocado. (As pilhas de chamadas estão actualmente disponíveis com um heap dump apenas com o Android 7.1 e inferior quando capturar o heap dump enquanto grava as alocações)
Para capturar um heap dump, clique em Dump Java heap na barra de ferramentas do Memory Profiler.Enquanto despeja o heap, a quantidade de memória Java pode aumentar temporariamente.Isto é normal porque o heap dump ocorre no mesmo processo que seu appand requer alguma memória para coletar os dados.
O heap dump aparece abaixo da linha de tempo da memória, mostrando todos os tipos de classe no heap, como mostrado na figura 5.
Figure 5. Visualizando o heap dump
Se você precisa ser mais preciso sobre quando o dump é criado, você pode criar um heap dump no ponto crítico do seu código de aplicação chamandodumpHprofData()
.
Na lista de classes, você pode ver as seguintes informações:
- Alocações: Número de alocações na pilha.
-
Tamanho nativo: Quantidade total de memória nativa usada por este tipo de objeto (em bytes). Esta coluna é visível apenas para o Android 7.0 e superior.
Você verá memória aqui para alguns objetos alocados em Java porque a memória nativa do Androidus para algumas classes de framework, tais como
Bitmap
. -
Shallow Size: Quantidade total de memória Java utilizada por este tipo de objeto (em bytes).
-
Retained Size: Tamanho total de memória sendo retida devido a todas as instâncias desta classe (em bytes).
Você pode usar os dois menus acima da lista de objetos alocados para escolher qual pilha é inspecionada e como organizar os dados.
No menu à esquerda, escolha qual pilha inspecionar:
- pilha padrão: Quando nenhuma pilha for especificada pelo sistema.
- app heap: A pilha primária na qual a sua aplicação aloca memória.
- pilha de imagens: A imagem de inicialização do sistema, contendo classes que são pré-carregadas durante o tempo de inicialização. As alocações aqui são garantidas para nunca mover ou ir embora.
- zygote heap: A copy-on-write heap onde um processo de aplicação é bifurcado no sistema Android.
No menu à direita, escolha como organizar as alocações:
- Organizar por classe: Agrupa todas as alocações com base no nome da classe. Este é o padrão.
- Arranjar por pacote: Agrupa todas as alocações baseadas no nome do pacote.
- Arranjar por pilha de chamadas: Agrupa todas as alocações em sua pilha de chamadas correspondente. Esta opção só funciona se você capturar o heap dump durante a gravação das alocações. Mesmo assim, é provável que existam objetos no heap que foram alocados antes de você começar a gravar, então essas alocações aparecem primeiro, simplesmente listadas pelo nome da classe.
A lista é ordenada pela coluna Retained Size por padrão. Para ordenar pelos valores em uma coluna diferente, clique no cabeçalho da coluna.
Clique em um nome de classe para abrir a janela Visão da Instância à direita(mostrado na figura 6). Cada instância listada inclui o seguinte:
- Profundidade: O menor número de lúpulos de qualquer raiz de GC para a instância selecionada.
- Tamanho nativo: Tamanho desta instância na memória nativa. Esta coluna é visível apenas para Android 7.0 e superior.
- Shallow Size: Tamanho desta instância na memória Java.
- Tamanho retido: Tamanho da memória que esta instância domina (conforme a árvore dominadora).
Figure 6. A duração necessária para capturar um heapdump é indicada na linha de tempo
Para inspecionar seu heapdump, siga estes passos:
- Na lista, encontre objetos que tenham contagens de heapdump invulgarmente grandes e que possam ser vazados. Para ajudar a encontrar classes conhecidas, clique no cabeçalho da coluna de classes Namecolumn para ordenar em ordem alfabética. Depois clique no nome de uma classe. O painelInstance View aparece à direita, mostrando cada instância dessa classe, como mostrado na figura 6.
- Alternativamente, você pode localizar objetos rapidamente clicando em Filter,ou pressionando Control+F (Command+F no Mac), e digitando uma classe ou nome de pacote no campo de busca. Você também pode procurar pelo nome do método se você selecionarArrange by callstack no menu suspenso. Se você quiser usar expressões regulares, marque a caixa ao lado de Regex. Marque a caixa ao lado da caixaMatch se a sua consulta de pesquisa for sensível a maiúsculas e minúsculas.
- No painel de Vista de Instância, clique numa instância. A guia Referências aparece abaixo, mostrando cada referência a esse objeto.
Or, clique na seta ao lado do nome da instância para visualizar todos os seus campos, e então clique em um nome de campo para visualizar todas as suas referências. Se você quiser ver o campo de detalhes da instância, clique com o botão direito do mouse no campo e selecione Ir para Instância.
- Na guia Referências, se você identificar uma referência que pode afetar a memória, clique com o botão direito do mouse sobre ela e selecione Ir para Instância. Isto selecciona a instância correspondente do despejo de pilha, mostrando-lhe os dados da sua própria instância.
No seu despejo de pilha, procure por fugas de memória causadas por qualquer um dos seguintes:
- Referências de longa duração a
Activity
,Context
,View
,Drawable
, e outros objectos que possam conter referências aActivity
ouContext
contentor. - Classes internas não estáticas, como um
Runnable
, que pode conterActivity
instância. - Caches que contêm objetos por mais tempo que o necessário.
Guardar um despejo de pilha como um arquivo HPROF
Após a captura de um despejo de pilha, os dados só são visíveis no Profiler de memória enquanto o profiler está rodando. Quando você sai da sessão de perfil, você perde o heap dump. Então, se você quiser salvá-lo para revisão mais tarde, exporte o heap dump para um arquivo HPROF. No Android Studio 3.1 e inferior, o botão Exportar captura para arquivo está no lado esquerdo da barra de ferramentas abaixo da linha de tempo; no Android Studio 3.2 e superior, há um botão Exportar Dump Heap Dump na altura de cada entrada Heap Dump no painel Sessions. No Export Asdialog que aparece, salve o arquivo com a extensão .hprof
file-name.
Para usar um analisador HPROF diferente comoejhat, você precisa converter o arquivo HPROF do formato Android para o formato Java SE HPROF. Você pode fazer isso com a ferramenta hprof-conv
fornecida no diretórioandroid_sdk/platform-tools/
. Execute o comando hprof-conv
com dois argumentos: o arquivo HPROF original e o local para escrever o arquivo HPROF convertido. Por exemplo:
hprof-conv heap-original.hprof heap-converted.hprof
Importar um arquivo heap dump
Para importar um arquivo HPROF (.hprof
), clique em Start a new profiling session no painelSessions, selecione Load from file, e escolha o arquivo do filebrowser.
Você também pode importar um arquivo HPROF arrastando-o do navegador de arquivos para a janela do aneditor.
Detecção de fugas no Memory Profiler
Quando analisar um despejo de pilha no Memory Profiler, pode filtrar os perfis que o Android Studio pensa que possam indicar fugas de memória para Activity
e Fragment
instâncias na sua aplicação.
Os tipos de dados que o filtro mostra incluem o seguinte:
-
Activity
instâncias que foram destruídas mas ainda estão sendo referenciadas. -
Fragment
instâncias que não têm um válidoFragmentManager
mas ainda estão sendo referenciadas.
Em certas situações, como as seguintes, o filtro pode produzir falsospositivos:
- A
Fragment
é criado mas ainda não foi utilizado. - A
Fragment
está a ser colocado em cache mas não como parte de umFragmentTransaction
.
Para utilizar esta funcionalidade, primeiro capture um dumpor heap importe um ficheiro heap dump para o Android Studio. Para exibir os fragmentos e atividades que talvez vazem memória, selecione a caixa de seleção Activity/Fragment Leaks no painel heapdump do Memory Profiler, como mostrado na figura 7.
>
Figure 7. Filtrando um heapdump para vazamentos de memória.
Técnicas para traçar o perfil da sua memória
>
Embora utilize o Memory Profiler, você deve enfatizar seu código de aplicação e tentar forcingmemory leaks. Uma maneira de provocar vazamentos de memória em sua aplicação é deixá-la rodar por um tempo antes de inspecionar a pilha. Os vazamentos podem chegar até o topo das alocações na pilha. No entanto, quanto menor o vazamento, mais tempo você precisa torcer a aplicação para vê-la.
Você também pode provocar um vazamento de memória de uma das seguintes maneiras:
- Rotate o dispositivo do retrato para a paisagem e volte várias vezes enquanto estiver em diferentes estados de atividade. A rotação do dispositivo pode muitas vezes causar um vazamento de um objeto
Activity
,Context
, ouView
, porque o sistema cria o objetoActivity
e se você segurar uma referência a um desses objetos em outro lugar, o sistema não pode coletar o lixo. - Comutar entre a sua aplicação e outra aplicação em diferentes estados de atividade (navegue para a telaHome, depois retorne à sua aplicação).
Tip: Você também pode executar os passos acima usando o framework de teste do programa.