Back home

Otimizando o tempo de inicialização do aplicativo

Otimize o tempo de inicialização do aplicativo

otimizando o tempo de inicialização do aplicativo

https://developer.apple.com/videos/play/wwdc2016/406/

[Música] Bom dia e bem-vindo à sessão 406, Otimizando o tempo de inicialização do aplicativo. [Música] Bom dia a todos e bem-vindos à Aula 406: Otimizando o tempo de inicialização de aplicativos.

Meu nome é Nick Kledzik, e hoje meu colega Louis e eu vamos levá-lo em um tour guiado sobre como um processo é iniciado. Meu nome é Nick Kledzik, e hoje meu colega Louis e eu vamos levá-lo em um tour sobre como um processo é iniciado.

Agora você deve estar se perguntando: este tópico é adequado para mim. Agora você pode estar pensando: este tópico é adequado para mim?

Então, pedimos que nossa equipe de marketing de desenvolvimento de crack fizesse algumas pesquisas e eles determinaram que há três grupos que se beneficiarão ao ouvir esta palestra. Então, pedimos que nossa incrível equipe de marketing fizesse algumas pesquisas e eles determinaram que havia três grupos de pessoas que se beneficiariam ao ouvir essa palestra.

O primeiro são os desenvolvedores de aplicativos que possuem um aplicativo que inicia muito lentamente. O primeiro é um desenvolvedor de aplicativos cujo lançamento é lento.

O segundo grupo são os desenvolvedores de aplicativos que não querem estar no primeiro grupo [risos]. O segundo grupo são os desenvolvedores de aplicativos que não querem estar no primeiro grupo [risos].

E, por último, qualquer pessoa que esteja realmente curiosa sobre como o sistema operacional funciona. Por fim, quem está curioso para saber como funciona um sistema operacional?

Então essa palestra vai ser dividida em duas seções, a primeira é mais teórica e a segunda mais prática, farei a primeira parte teórica. Então essa palestra vai ser dividida em duas partes, a primeira parte é mais teórica e a segunda parte é mais prática, vou falar da primeira parte.

E nele estarei acompanhando você por todas as etapas que acontecem, até a principal. Vou guiá-lo por todas as etapas que acontecem, até o corpo principal.

Mas para que você entenda e aprecie todas as etapas, primeiro preciso ministrar um curso intensivo sobre Mach-O e Memória Virtual. Mas para que você entenda e aprecie isso, primeiro preciso ministrar um curso intensivo sobre computação analógica e memória virtual.

Então, primeiro alguma terminologia Mach-O, rapidamente. Primeiro, alguma terminologia Mach-O.

Mach-O é um monte de tipos de arquivos para diferentes executáveis ​​em tempo de execução. Mach-O é um conjunto de tipos de arquivos para diferentes executáveis ​​de tempo de execução.

Portanto, o primeiro executável, que é o binário principal em um aplicativo, é também o binário principal em uma extensão de aplicativo. O primeiro arquivo executável é o arquivo binário principal no aplicativo e o arquivo binário principal na extensão do aplicativo.

Um dylib é uma biblioteca dinâmica; em outras plataformas, você pode conhecê-las como DSOs ou DLLs. Um dylib é uma biblioteca dinâmica e em outras plataformas você pode conhecê-la como DSOs ou dlls.

Nossa plataforma também possui outro tipo de coisa chamada pacote. Nossa plataforma também possui outra coisa chamada pacote.

Agora, um pacote é um tipo especial de dylib ao qual você não pode vincular, tudo o que você pode fazer é carregá-lo em tempo de execução por um dlopen e é usado em um Mac OS para plug-ins. Um pacote é um dylib especial ao qual você não pode vincular, tudo o que você pode fazer é carregá-lo em tempo de execução via dlopen, que é usado para plug-ins no Mac OS.

Por último, está o termo imagem. Finalmente há imagens.

A imagem refere-se a qualquer um desses três tipos. A imagem refere-se a qualquer um desses três tipos.

E usarei muito esse termo. Vou usar muito essa palavra.

E por último, o termo framework está muito sobrecarregado em nossa indústria, mas neste contexto, um framework é um dylib com uma estrutura de diretório especial ao seu redor para armazenar os arquivos necessários para esse dylib. Finalmente, o termo framework está muito sobrecarregado em nossa indústria, mas neste contexto, um framework é um dylib que possui uma estrutura de diretório especial ao seu redor para armazenar os arquivos que esse dylib precisa.

Então, vamos mergulhar direto no formato de imagem Mach-O. Vamos direto ao formato de imagem Mach-O.

Uma imagem Mach-O é dividida em segmentos; por convenção, todos os nomes de segmentos usam letras maiúsculas. Uma imagem Mach-O é segmentada em segmentos e, por convenção, todos os nomes dos segmentos estão em letras maiúsculas.

Agora, cada segmento é sempre um múltiplo do tamanho da página, neste exemplo o texto tem 3 páginas, os DATA e LINKEDIT são cada uma página. Agora, cada segmento é sempre um múltiplo do tamanho da página, neste exemplo o texto tem 3 páginas e os dados e LINKEDIT têm 1 página.

Agora o tamanho da página é determinado pelo hardware, para arm64 o tamanho da página é 16K, todo o resto é 4k. Agora o tamanho da página é determinado pelo hardware, para arm64 o tamanho da página é 16K, outros são 4k.

Agora, outra maneira de ver a coisa são as seções. Outra abordagem é a segmentação.

Portanto, seções são algo que o compilador omite. Portanto, parte disso é ignorada pelo compilador.

Mas as seções são, na verdade, apenas um subintervalo de um segmento, não têm nenhuma restrição de tamanho de página, mas não se sobrepõem. Mas a seção é na verdade apenas um subintervalo de um segmento. Eles não têm limite de tamanho de página, mas não se sobrepõem.

Agora, os nomes de segmento mais comuns são TEXT, DATA, LINKEDIT; na verdade, quase todo binário possui exatamente esses três segmentos. Hoje em dia, os nomes de segmentos mais comuns são TEXT, DATA e LINKEDIT. Na verdade, quase todo binário possui esses três segmentos.

Você pode adicionar outros personalizados, mas geralmente não agrega nenhum valor. Você pode adicionar valores personalizados, mas normalmente nenhum valor será adicionado.

Então, para que são usados? Bem, TEXT está no início do arquivo, contém o cabeçalho Mach, contém quaisquer instruções de máquina, bem como qualquer constante somente leitura, como strings c. Para que servem isso? O texto está no início do arquivo e contém o cabeçalho Mach, que contém quaisquer instruções de máquina, bem como constantes somente leitura, como strings c.

O segmento DATA é reescrito, o segmento DATA contém todas as suas variáveis ​​globais. O segmento de dados é reescrito e contém todas as variáveis ​​globais.

E por último, está o LINKEDIT. Finalmente, LINKEDIT.Agora o LINKEDIT não contém suas funções de variáveis ​​globais, um LINKEDIT contém informações sobre suas funções de variáveis, como nome e endereço. LINKEDIT não contém funções de variáveis ​​globais, contém informações sobre funções de variáveis, como seus nomes e endereços.

Você também já deve ter ouvido falar em arquivos universais, o que são? Bem, suponha que você crie um aplicativo iOS, para 64 bits, e agora tenha esse arquivo Mach-O, então o que acontece no próximo código quando você diz que também deseja construí-lo para dispositivos de 32 bits? Quando você reconstruir, o Xcode criará outro arquivo Mach-O separado, este construído para 32 bits, RB7. Você também já deve ter ouvido falar em arquivos universais, o que são? Digamos que você criou um aplicativo iOS para 64 bits e agora tem esse arquivo Mach-O. O que acontece a seguir quando você diz que deseja construí-lo também para dispositivos de 32 bits? Quando você reconstruir, o Xcode criará outro arquivo Mach-O separado, este criado para RB7 de 32 bits.

E então esses dois arquivos são mesclados em um terceiro arquivo, chamado arquivo universal Mach-O. Esses dois arquivos são então mesclados em um terceiro arquivo denominado arquivo universal Mach-O.

E isso tem um cabeçalho no início, e todo o cabeçalho tem uma lista de todas as arquiteturas e quais são seus deslocamentos no arquivo. Possui um cabeçalho no início com uma lista de todas as arquiteturas e seus deslocamentos no arquivo.

E esse cabeçalho também tem o tamanho de uma página. O título também tem o tamanho de uma página.

Agora você deve estar se perguntando: por que os segmentos têm vários tamanhos de página? Por que o cabeçalho tem um tamanho de página e está desperdiçando muito espaço. Agora você deve estar se perguntando: por que os segmentos têm vários tamanhos de página? Por que os cabeçalhos têm o mesmo tamanho de página, isso desperdiça muito espaço.

Bem, a razão pela qual tudo é baseado em páginas tem a ver com o nosso próximo tópico, que é memória virtual. A razão pela qual tudo é baseado em páginas está relacionada ao nosso próximo tópico: memória virtual.

Então, o que é memória virtual? Alguns de vocês devem conhecer o ditado da engenharia de software de que todo problema pode ser resolvido adicionando um nível de indireção. Então, o que é memória virtual? Alguns de vocês devem conhecer o ditado da engenharia de software de que todo problema pode ser resolvido adicionando um nível de indireção.

Então o problema que a memória virtual resolve é como você gerencia toda a sua RAM física quando tem todos esses processos? Então eles adicionaram um pouco de indireção. Então o problema que a memória virtual resolve é: como você gerencia toda a RAM física quando tem todos esses processos? Então eles adicionam alguma indireção.

Cada processo é um espaço de endereço lógico que é mapeado para alguma página física da RAM. Cada processo é um espaço de endereço lógico, mapeado para uma determinada página física da RAM.

Agora, esse mapeamento não precisa ser um para um, você pode ter endereços lógicos que não vão para nenhuma RAM física e pode ter vários endereços lógicos que vão para a mesma RAM física. Agora, esse mapeamento não precisa ser um para um, você pode ter endereços lógicos que não vão para a RAM física ou pode ter vários endereços lógicos que vão para a mesma RAM física.

Isso ofereceu muitas oportunidades aqui. Isso oferece muitas oportunidades.

Então, o que você pode fazer com VM? Bem, primeiro, se você tiver um endereço lógico que não mapeia para nenhuma RAM física, quando você acessa esse endereço em seu processo, ocorre uma falha de página. Então, o que uma VM pode fazer? Primeiro, se houver um endereço lógico que não esteja mapeado para nenhuma RAM física e quando você acessar esse endereço em um processo, ocorrerá uma falha de página.

Nesse ponto, o kernel interrompe o thread e tenta descobrir o que precisa acontecer. Neste ponto, o kernel interrompe o thread e tenta descobrir o que precisa acontecer.

O próximo passo é que se você tiver dois processos, com endereços lógicos diferentes, mapeados para a mesma página física, esses dois processos agora compartilharão o mesmo bit de RAM. Em seguida, se você tiver dois processos com endereços lógicos diferentes, mapeados para a mesma página física, ambos os processos compartilharão os mesmos bits de RAM.

Agora você tem compartilhamento entre processos. Agora você pode compartilhar entre processos.

Outro recurso interessante é o mapeamento baseado em arquivo. Outro recurso interessante é o mapeamento de suporte a arquivos.

Em vez de realmente ler um arquivo inteiro na RAM, você pode informar ao sistema VM por meio da chamada mmap, quero que essa fatia desse arquivo seja mapeada para esse intervalo de endereços em meu processo. Você pode informar ao sistema VM por meio da chamada mmap que, em vez de ler o arquivo inteiro na RAM, quero que essa parte do arquivo seja mapeada para esse intervalo de endereços no processo.

Então, por que você faria isso? Bem, em vez de ter que ler o arquivo inteiro, tendo esse mapeamento configurado, conforme você acessa primeiro esses endereços diferentes, como se você tivesse lido na memória, cada vez que você acessa um endereço que não foi acessado antes, causará uma falha de página, o kernel lerá apenas aquela página. Então, por que você faria isso? Em vez de ter que ler o arquivo inteiro, configurado pelo mapa, ao acessar pela primeira vez esses diferentes endereços, se você lê-lo na memória, cada vez que acessar um endereço que não foi acessado antes, causará uma falha de página e o kernel lerá uma página.

E isso proporciona uma leitura preguiçosa do seu arquivo. Isso deixará você com preguiça de ler seu documento.

Agora podemos juntar todos esses recursos, e o que eu disse sobre Mach-O agora você percebe que o segmento TEXT de qualquer dylib ou imagem pode ser mapeado em vários processos, será lido preguiçosamente e todas essas páginas podem ser compartilhadas entre esses processos. Agora podemos reunir todos esses recursos, e eu disse Mach-o, agora você percebe que o segmento de texto de qualquer dylib ou imagem pode ser mapeado em vários processos, será lido preguiçosamente e todas essas páginas podem ser compartilhadas entre esses processos.

E o segmento DATA? O segmento DATA é lido, escrito, então para isso temos um truque chamado copiar na gravação, é meio parecido com a clonagem vista no sistema de arquivos da Apple. E quanto ao segmento de dados? O segmento de dados é lido e gravado, então temos o que é chamado de técnica de cópia na gravação, que é um pouco semelhante à clonagem vista no sistema de arquivos da Apple.O que copiar e escrever faz é compartilhar de maneira otimista a página DATA entre todos os processos. O que a cópia e a gravação fazem é compartilhar páginas de dados de maneira otimista entre todos os processos.

O que acontece quando um processo, desde que esteja apenas lendo as variáveis ​​globais que o compartilhamento funciona. O que acontece quando um processo compartilha trabalho, desde que leia apenas variáveis ​​globais.

Mas assim que um processo realmente tenta gravar em sua página DATA, a cópia e a gravação acontecem. Mas assim que um processo realmente tenta gravar em suas páginas de dados, ocorre uma cópia e gravação.

A cópia e gravação faz com que o kernel faça uma cópia dessa página em outra RAM física e redirecione o mapeamento para lá. Copiar e gravar fazem com que o kernel copie a página para outra RAM física e redirecione o mapeamento para essa RAM física.

Portanto, esse processo agora possui sua própria cópia dessa página. Portanto, um processo agora possui sua própria cópia da página.

O que nos leva a páginas limpas versus páginas sujas. Isso nos leva à página limpa e suja.

Portanto, essa cópia é considerada uma página suja. Portanto, essa cópia é considerada uma página suja.

Uma página suja é algo que contém informações específicas do processo. Páginas sujas são páginas que contêm informações específicas do processo.

Uma página limpa é algo que o kernel pode regenerar posteriormente, se necessário, como reler o disco. Uma página limpa é aquela que o kernel pode regenerar se necessário posteriormente, como reler do disco.

Portanto, as páginas sujas são muito mais caras do que as páginas limpas. Portanto, as páginas sujas são muito mais caras do que as páginas limpas.

E a última coisa é que os limites de permissão estão nos limites da página. O ponto final é que os limites de permissão estão nos limites da página.

Com isso quero dizer que as permissões permitem marcar uma página como legível, gravável ou executável, ou qualquer combinação deles. O que quero dizer com permissões é que você pode marcar uma página como legível, gravável, executável ou qualquer combinação destes.

Então vamos juntar tudo isso, falei sobre o formato Mach-O, algo sobre memória virtual, vamos ver como eles funcionam juntos. Vamos juntar isso, falei sobre o formato Mach-O, um pouco sobre memória virtual, e vamos ver como eles funcionam juntos.

Agora vou avançar e falar um pouco sobre como o dyld funciona e em alguns momentos irei explicar isso, mas por enquanto, só quero mostrar como isso mapeia entre Mach-O e memória virtual. Agora vou pular um pouco e falar um pouco sobre como o dyld funciona, e explicarei isso detalhadamente em um momento, mas por enquanto, só quero mostrar como isso mapeia entre Mach-O e memória virtual.

Portanto, temos um arquivo dylib aqui e, em vez de lê-lo na memória, mapeamos-o na memória. Temos um arquivo dylib aqui e, em vez de lê-lo na memória, mapeamos-o na memória.

Então, na memória esse dylib ocuparia oito páginas. Na memória, este dylib ocupa 8 páginas.

A economia, porque é diferente são esses ZeroFills. O que o torna diferente são esses preenchimentos zero.

Acontece que a maioria das variáveis ​​globais são zero inicialmente. Portanto, a maioria das variáveis globais começa como 0.

Portanto, o static [inaudível] faz uma otimização que move todas as variáveis globais zero para o final e não ocupa espaço em disco. Portanto, o static [inaudível] foi otimizado para mover todas as 0 variáveis ​​globais para o final e não ocupar espaço em disco.

E em vez disso, usamos o recurso VM para informar à VM que na primeira vez que esta página for acessada, preencha-a com zeros. Em vez disso, usamos um recurso de VM para instruir a VM a preenchê-lo com zeros na primeira vez que acessar esta página.

Portanto, não requer leitura. Portanto, não requer leitura.

Portanto, a primeira coisa que o dyld precisa fazer é olhar o cabeçalho Mach, na memória, neste processo. Portanto, a primeira coisa que o dyld faz é observar o cabeçalho Mach na memória durante esse processo.

Então ele estará olhando para a caixa superior da memória, quando isso acontecer, não há nada lá, não há mapeamento para uma página física, então ocorre uma falha de página. Ele verá a caixa superior na memória e quando isso acontecer, não há nada lá, nenhum mapeamento para a página física, então ocorre a falha de página.

Nesse ponto, o kernel percebe que isso está mapeado para um arquivo, então ele lê a primeira página do arquivo, coloca-o na RAM física e define o mapeamento para ele. Neste ponto, o kernel percebe que o mapa é para um arquivo, então ele lê a primeira página do arquivo, coloca-o na RAM física e configura o mapa para ele.

Agora o dyld pode realmente começar a ler o cabeçalho Mach. Agora, dyld pode começar a ler o cabeçalho Mach.

Ele lê o cabeçalho Mach, o cabeçalho Mach diz: ah, há algumas informações no segmento LINKEDIT que você precisa examinar. Ele lerá o cabeçalho Mach, e o cabeçalho Mach dirá que há algumas informações no fragmento LINKEDIT que ele precisa ver.

Então, novamente, dyld mostra o que está na caixa inferior no processo um. Mais uma vez, dyld coloca o conteúdo da caixa inferior do processo 1.

O que novamente causa uma falha de página. Isso causará novamente uma falha de página.

O Kernel atende lendo outra página física da RAM, o LINKEDIT. O kernel o atende lendo em outra página física LINKEDIT da RAM.

Agora dyld pode esperar um LINKEDIT. Agora, dyld pode esperar pelo LINKEDIT.

Agora em processo, o LINKEDIT dirá ao dyld, você precisa fazer alguns ajustes nesta página DATA para tornar este dylib executável. Agora, durante este processo, o LINKEDIT dirá ao dyld que você precisa fazer algumas correções nesta página de dados para tornar este dylib executável.

Então acontece a mesma coisa, dyld está agora, lê alguns dados da página DATA, mas tem algo diferente aqui. Acontece a mesma coisa, dyld agora lê alguns dados da página de dados, mas algo está diferente aqui.

dyld na verdade vai escrever algo de volta, na verdade vai mudar a página DATA e, neste ponto, acontece uma cópia na gravação. dyld escreverá algo de volta, mudará a página de dados e, neste momento, ocorrerá cópia na gravação.

E esta página fica suja. Esta página está ficando suja.Então, o que seriam 8 páginas de RAM suja se eu apenas malocasse oito páginas e depois lesse o material nelas, eu teria oito páginas de RAM suja. Então, qual é a memória suja de 8 páginas? Se eu perder 8 páginas e depois ler, terei 8 páginas de memória suja.

Mas agora só tenho uma página de RAM suja e duas páginas limpas. Mas agora só tenho uma página de memória suja e duas páginas de memória limpa.

Então, o que acontecerá quando o segundo processo carregar o mesmo dylib. Então, o que acontece quando o segundo processo carrega o mesmo dylib.

Portanto, no segundo processo, o dyld segue as mesmas etapas. Na segunda passagem, dyld segue as mesmas etapas.

Primeiro ele olha para o cabeçalho Mach, mas desta vez o kernel diz, ah, eu já tenho aquela página na RAM em algum lugar, então ele simplesmente redireciona o mapeamento para reutilizar aquela página, nenhum iO foi feito. Primeiro ele olha para o cabeçalho Mach, mas desta vez o kernel diz, ah, eu já tenho aquela página em algum lugar da RAM, então ele apenas redireciona o mapa para reutilizar aquela página, sem iOs.

O mesmo acontece com o LINKEDIT, é muito mais rápido. Assim como o LINKEDIT, é mais rápido.

Agora chegamos à página DATA, neste ponto o kernel tem que olhar para ver se a página DATA, a cópia limpa já existe em algum lugar na RAM, e se existir pode reutilizá-la, caso contrário, tem que relê-la. Agora vamos dar uma olhada na página de dados, neste ponto o kernel tem que olhar a página de dados e ver se ainda existe uma cópia limpa em algum lugar da RAM, se existir, ele pode reutilizá-la, caso contrário, deve relê-la.

E agora, neste processo, o dyld irá sujar a RAM. No processo, o dyld polui a RAM.

Agora, a última etapa é que o LINKEDIT só é necessário enquanto o dyld está realizando suas operações. A última etapa é LINKEDIT, que só é necessária quando dyld executa a operação.

Assim, ele pode sugerir ao kernel, uma vez concluído, que ele realmente não precisa mais dessas páginas LINKEDIT, você pode recuperá-las quando alguém precisar de RAM. Isso pode sugerir ao kernel que, uma vez concluído, ele não precisará mais dessas páginas LINKEDIT e você poderá recuperá-las quando alguém precisar da RAM.

Portanto, o resultado é que agora temos dois processos compartilhando esses dylibs, cada um teria oito páginas, ou um total de 16 páginas sujas, mas agora temos apenas duas páginas sujas e uma página limpa e compartilhada. O resultado é que agora temos dois processos compartilhando esses dylibs, cada um com 8 páginas, ou 16 páginas sujas no total, mas agora temos apenas duas páginas sujas e uma página limpa compartilhada.

Duas outras coisas menores que quero abordar é como a segurança afeta o dyld, essas duas grandes coisas de segurança que impactaram o dyld. As outras duas pequenas coisas sobre as quais quero falar são como a segurança afeta o dyld, e essas duas grandes coisas afetam o dyld.

Então, um é ASLR, randomização de layout de espaço de endereço, esta é uma tecnologia antiga de uma ou duas décadas, onde basicamente você randomiza o endereço de carregamento. Um deles é ASLR, Address Space Layout Randomization, que é uma tecnologia de dez a vinte anos atrás onde basicamente você randomiza endereços de carregamento.

A segunda é a assinatura de código, é necessário, muitos de vocês tiveram que lidar com a assinatura de código, no Xcode, e pensam na assinatura de código como executar um hash criptográfico em todo o arquivo e, em seguida, assiná-lo com sua assinatura. A segunda é a assinatura de código. Muitas pessoas lidaram com assinatura de código no Xcode. A assinatura de código consiste apenas em executar um hash criptográfico em todo o arquivo e depois assiná-lo com uma assinatura.

Bem, para validar esse tempo de execução, isso significa que todo o arquivo teria que ser relido. Para verificar o tempo de execução, isso significa que todo o arquivo deve ser relido.

Então, em vez disso, o que realmente acontece no momento da construção é que cada página do seu arquivo Mach-O recebe seu próprio hash criptográfico individual. Então, o que realmente acontece no momento da construção é que cada página do arquivo Mach-O possui seu próprio hash criptográfico.

E todos esses hashes são armazenados no LINKEDIT. Todas essas tabelas hash são armazenadas no LINKEDIT.

Isso permite que cada página seja validada de que não foi adulterada e que era de sua propriedade naquele momento. Isso verifica cada página para garantir que ela não tenha sido adulterada e seja aquela que você possuía quando estava na página.

Ok, terminamos o curso intensivo, agora vou orientá-lo do executivo ao principal. Ok, concluímos o curso intensivo, agora vou levá-lo do executivo ao principal.

Então, o que é executivo? Exec é uma chamada de sistema. Então, o que é executivo? Exec é uma chamada de sistema.

Quando você entra no kernel, basicamente diz que quero substituir esse processo por este novo programa. Quando você ficar preso no kernel, você pode basicamente dizer que quero substituir este processo por este novo programa.

O kernel limpa todo o espaço de endereço e mapeia o executável que você especificou. O kernel limpa e mapeia todo o espaço de endereço no executável especificado.

Agora, para ASLR, ele mapeia em um endereço aleatório. Para ASLR, ele mapeia para um endereço aleatório.

A próxima coisa que ele faz é partir daquele aleatório, de volta a zero, ele marca toda a região como inacessível, e com isso quero dizer que está marcado como não legível, não gravável, não executável. A próxima coisa que ele faz é partir daquele aleatório, de volta a 0, marcando toda a área como inacessível, quero dizer, marcando-a como ilegível, não gravável, inexecutável.

O tamanho dessa região é de pelo menos 4 KB para processos de 32 bits e pelo menos 4 GB para processos de 64 bits. O tamanho desta área deve ser de pelo menos 4 KB para processos de 32 bits e 4 GB para processos de 64 bits.

Isso captura qualquer referência de ponteiro NULL e também prevê mais bits, captura qualquer truncamento de ponteiro. Ele captura qualquer referência de ponteiro nulo e, prevendo mais bits, captura qualquer truncamento de ponteiro.

Agora, a vida foi fácil nas primeiras décadas de Unix, porque tudo que faço é mapear um programa, instalar o PC nele e começar a executá-lo. Nas primeiras décadas, a vida no Unix era simples porque tudo que eu fazia era mapear um programa, colocar meu PC nele e começar a executá-lo.

E então foram inventadas as bibliotecas compartilhadas. Então, foram inventadas bibliotecas compartilhadas.Então, quem carrega dylibs? Eles rapidamente perceberam que ficaram realmente complicados e o pessoal do kernel não queria que o kernel fizesse isso, então, em vez disso, um programa auxiliar foi criado. Então, quem instalou os dylibs? Eles rapidamente perceberam que estavam ficando muito complexos e que o pessoal do kernel não queria que o kernel fizesse isso, então um programa auxiliar foi criado.

Em nossa plataforma é chamado dyld. Nossa plataforma se chama dyld.

Em outros Unix você pode conhecê-lo como LD. Em outros Unixes você pode conhecê-lo como LD.

então. Então.

Então, quando o kernel termina de mapear um processo, ele agora mapeia outro Mach-O chamado dyld para esse processo em outro endereço aleatório. Assim, quando o kernel terminar de mapear o processo, ele agora mapeia outro Mach-O chamado dyld para o processo em outro endereço aleatório.

Coloca o PC em dyld e vamos terminar de iniciar o processo. Configure o PC para dyld e deixe o dyld terminar de iniciar o processo.

Então agora o dyld está em execução e seu trabalho é carregar todos os dylibs dos quais você depende e deixar tudo preparado e funcionando. Agora que o dyld está em execução, seu trabalho é carregar todos os dylibs dos quais você depende e deixar tudo pronto e funcionando.

Então, vamos percorrer essas etapas. Vejamos as etapas.

Este é um monte de etapas e tem uma espécie de linha do tempo na parte inferior aqui. À medida que avançamos, percorreremos a linha do tempo. É uma série de etapas e tem uma linha do tempo na parte inferior e à medida que passamos por elas, percorremos a linha do tempo.

Então, a primeira coisa é que o dyld precisa mapear todos os dylibs dependentes. Primeiro, o dyld precisa mapear todos os dylibs dependentes.

Bem, quais são os dylibs dependentes? Para encontrá-los, primeiro ele lê o cabeçalho do executável principal que o kernel já mapeou nesse cabeçalho é uma lista de todas as bibliotecas dependentes. O que são dylibs dependentes? Para encontrar esses arquivos, ele primeiro lê o cabeçalho executável principal que o kernel mapeou para esse cabeçalho de arquivo, que é uma lista de todas as bibliotecas dependentes.

Então é preciso analisar isso. Precisa ser analisado.

Então ele tem que encontrar cada dylib. Então ele tem que encontrar cada dylib.

E uma vez encontrado cada dylib, ele precisa abrir e executar o início de cada arquivo, precisa ter certeza de que é um arquivo Mach-O, validá-lo, encontrar sua assinatura de código, registrar essa assinatura de código no kernel. Depois de encontrar cada dylib, ele precisa abrir e executar o início de cada arquivo, precisa ter certeza de que é um arquivo Mach-O, verificá-lo, encontrar sua assinatura de código e registrar a assinatura de código no kernel.

E então ele pode chamar mmap em cada segmento desse dylib. Então ele pode chamar mmap em todos os segmentos do dylib.

Ok, isso é muito simples. Muito simples.

Seu aplicativo sabe sobre o kernel dyld, dyld então diz oh, este aplicativo depende de A e B dylib, carregue os dois, terminamos. Seu aplicativo conhece o dyld do kernel, e então dyld diz, este aplicativo depende dos dylibs A e B, carregue esses dois e pronto.

Bem, fica mais complicado, porque A. Fica mais complicado porque A.

dylib e B. dylib e B.

Os próprios dylib podem depender dos dylibs. os próprios dylibs podem depender dos dylibs.

Então dyld tem que fazer a mesma coisa novamente para cada um desses dylibs, e cada um dos dylibs pode depender de algo que já está carregado ou de algo novo, então ele tem que determinar se já está carregado ou não, e se não, ele precisa carregá-lo. Então dyld tem que fazer a mesma coisa para cada dylib, cada dylib pode depender de algo já carregado ou recém-carregado, então ele tem que determinar se já está carregado e se não, precisa carregá-lo.

Então, isso continua indefinidamente. Isso continua.

E eventualmente ele tem tudo carregado. Eventualmente, carregou tudo.

Agora, se você olhar para um processo, o processo médio em nosso sistema carrega algo entre 1 e 400 dylibs, então são muitos dylibs para serem carregados. Agora, se você olhar para um processo, o processo médio em nosso sistema tem entre 1 e 400 dylibs carregados, então são muitos dylibs para carregar.

Felizmente, a maioria deles são dylibs de sistema operacional, e trabalhamos muito ao construir o sistema operacional para pré-calcular e pré-armazenar em cache grande parte do trabalho que o dyld precisa fazer para carregar essas coisas. Felizmente, a maioria deles são dylibs de sistema operacional e trabalhamos muito ao construir o sistema operacional para pré-calcular e pré-armazenar em cache grande parte do trabalho necessário para o dyld carregar essas coisas.

Portanto, os dylibs do sistema operacional carregam muito, muito rapidamente. Portanto, os dylibs do sistema operacional carregam muito rápido.

Então agora carregamos todos os dylibs, mas eles estão todos flutuando, independentes uns dos outros, e agora temos que ligá-los. Agora que temos todos os dylibs carregados, mas todos em seus próprios carros alegóricos, precisamos juntá-los.

Isso é chamado de consertos. Isto é o que é chamado pode ser arranjado.

Mas uma coisa sobre os consertos é que aprendemos que, por causa da assinatura do código, não podemos realmente alterar as instruções. Mas uma coisa que aprendemos sobre como consertar é que não podemos alterar as instruções por causa da assinatura do código.

Então, como um dylib chama outro dylib se você não pode alterar as instruções de como ele chama? Bem, ligamos de volta ao nosso velho amigo e acrescentamos muitas indiretas antigas. Então, como um dylib chama outro dylib se você não pode alterar as instruções de como ele é chamado? Bem, vamos ligar de volta para um velho amigo e lançar um monte de discurso indireto.

Portanto, nossa geração de código é chamada de PIC dinâmico. Portanto, nossa geração de código é chamada de PIC dinâmico.

É um código independente posicionado, o que significa que o código pode ser carregado no endereço e é dinâmico, o que significa que as coisas são endereçadas indiretamente. É um código independente de localização, o que significa que o código pode ser carregado em endereços, e dinâmico, o que significa que as coisas são endereçadas indiretamente.O que isso significa é chamar uma coisa para outra, o co-gerador na verdade cria um ponteiro no segmento DATA e esse ponteiro aponta para o que você deseja chamar. Isso significa que para chamar de uma coisa para outra, a co-geração na verdade cria um ponteiro no segmento de dados que aponta para a coisa a ser chamada.

O código carrega esse ponteiro e salta para ele. O código carrega esse ponteiro e vai até ele.

Então tudo o que o dyld está fazendo é consertar ponteiros e dados. Então o que o dyld faz é corrigir os ponteiros e os dados.

Agora, existem duas categorias principais de ajustes, rebase e vinculação, então qual é a diferença? Portanto, rebase é que se você tiver um ponteiro apontando para sua imagem e quaisquer ajustes necessários para isso, o segundo será vinculativo. Agora, existem dois tipos principais de correções, rebase e vinculação, então qual é a diferença? Então, se você tem um ponteiro para sua imagem e precisa de algum ajuste, o segundo é vinculativo.

Vinculação é se você estiver apontando algo fora da sua imagem. Vinculação é quando você aponta para algo fora da sua imagem.

E cada um deles precisa ser consertado de maneira diferente, então seguirei as etapas. Cada um deles exige uma correção diferente, então abordarei as etapas uma por uma.

Mas primeiro, se você estiver curioso, há um comando, dyld info, com várias opções. Mas primeiro, se você estiver curioso, há um comando, dyld info, com muitas opções.

Você pode executar isso em qualquer binário e verá todos os ajustes que o dyld terá que fazer para que esse binário o prepare. Você pode executar isso em qualquer binário e verá todas as modificações feitas por dyld nesse binário.

Então, rebaseando. Então, reavaliando.

Bem, na velhice, você poderia especificar um endereço de carregamento preferido para cada dylib, e esse endereço de carregamento preferido era o vinculador estático e o dyld trabalhavam juntos de forma que, se você carregasse, para esse endereço de carregamento preferido, todos os ponteiros e dados que deveria codificar internamente, estavam corretos e o dyld não teria que fazer nenhum conserto. Na velhice, você pode especificar o endereço de carregamento prioritário para cada dylib, e o endereço de carregamento prioritário é o vinculador estático e o dyld funciona juntos. Se você carregar, o endereço de carregamento prioritário, todos os ponteiros e dados devem estar no código interno, estar correto e o dyld não precisa fazer nada para organizá-lo.

Mas hoje em dia, com ASLR, seu dylib é carregado em um endereço aleatório. Mas agora, com ASLR, seu dylib é carregado em um endereço aleatório.

Ele foi deslizado para algum outro endereço, o que significa que todos esses ponteiros e dados ainda estão apontados para o endereço antigo. Ele passou para outro endereço, o que significa que todos esses ponteiros e dados ainda apontam para o endereço antigo.

Então, para consertar isso, precisamos calcular o slide, que é o quanto ele se moveu, e para cada um desses ponteiros internos, basicamente adicionar o valor do slide a eles. Para resolver esses problemas, precisamos calcular o slider, ou seja, quanto ele se moveu, e para cada ponteiro interno, precisamos somar o valor do slider a eles.

Portanto, rebase significa passar por todos os seus ponteiros de dados, que são internos, e basicamente adicionar um slide a eles. Portanto, realocar significa iterar todos os ponteiros de dados, que são internos, e basicamente adicionar um slide a eles.

Então o conceito é muito simples, ler, somar, escrever, ler, somar, escrever. O conceito é simples, ler, adicionar, escrever, ler, adicionar, escrever.

Mas onde estão esses indicadores de dados? Onde esses ponteiros estão no seu segmento, eles são codificados no segmento LINKEDIT. Mas onde estão esses indicadores de dados? Esses ponteiros estão no seu segmento, codificados no segmento LINKEDIT.

Agora, neste ponto, tudo o que tivemos foi tudo mapeado, então quando começamos a fazer o rebase, estamos na verdade causando falhas de página em todas as páginas DATA. Agora, neste ponto, o que temos é tudo mapeado, então quando começamos a fazer o rebase, estamos na verdade causando falhas de página em todas as páginas de dados.

E então causamos cópias e gravações à medida que as alteramos. Quando os alteramos, ocorrem cópias e gravações.

Portanto, o rebase às vezes pode ser caro por causa de todo o iO. Portanto, a realocação às vezes pode ser cara devido aos iOs.

Mas um truque que fazemos é fazê-lo sequencialmente e, do ponto de vista do kernel, ele vê falhas de dados acontecerem sequencialmente. Mas um truque que faremos é sequencialmente, então, da perspectiva do kernel, ele verá os erros de dados acontecendo sequencialmente.

E quando vê isso, o kernel está lendo adiante para nós, o que torna o iO menos dispendioso. Ao perceber isso, o kernel lê os dados para nós com antecedência, reduzindo o custo dos iOs.

O próximo passo é a ligação, a ligação é para ponteiros que apontam para fora do seu dylib. A seguir vem a ligação, que é um ponteiro para fora do dylib.

Na verdade, eles estão vinculados ao nome, na verdade são a string, neste caso, malloc armazenado na edição do link, que indica que esse ponteiro de dados precisa apontar para malloc. Na verdade, eles são vinculados por nome, na verdade são strings e, neste exemplo, malloc é armazenado na edição do link, que indica que esse ponteiro de dados precisa apontar para malloc.

Portanto, em tempo de execução, dyld precisa realmente encontrar a implementação desse símbolo, o que requer muitos cálculos, examinando tabelas de símbolos. Portanto, em tempo de execução, dyld precisa realmente encontrar a implementação desse símbolo, o que é computacionalmente intenso e requer a consulta da tabela de símbolos.

Depois de encontrados, os valores são armazenados nesse ponteiro de dados. Uma vez encontrado, esse valor é armazenado nesse ponteiro de dados.

Portanto, isso é muito mais complexo computacionalmente do que o rebase. Portanto, é muito mais complicado do que redirecionar.

Mas há muito pouco iO porque o rebase já fez a maior parte do iO. Mas existem muito poucos iOs porque Chongji já concluiu a maioria dos iOs.

Em seguida, ObjC tem um monte de estruturas DATA, estrutura de classe DATA que é um ponteiro para seus métodos e um ponteiro para um super brilho e assim por diante. Em seguida, ObjC tem um monte de estruturas de dados, as estruturas de dados da classe são ponteiros para seus métodos e ponteiros para superbrilhantes e assim por diante.Quase todos eles são corrigidos por meio de rebase ou vinculação. Quase todos estes são corrigidos via rebase ou vinculação.

Mas há algumas coisas extras que o tempo de execução do ObjC exige. Mas o tempo de execução do ObjC requer algo extra.

A primeira é que ObjC é uma linguagem dinâmica e você pode solicitar que uma classe seja fundamentada pelo nome. A primeira é que ObjC é uma linguagem dinâmica e você pode solicitar que uma classe seja confirmada pelo nome.

Isso significa que o tempo de execução do ObjC deve manter uma tabela com todos os nomes das classes para as quais eles são mapeados. Isso significa que o tempo de execução do ObjC deve manter uma tabela contendo todos os nomes das classes para as quais estão mapeados.

Então toda vez que você carrega algo, ele define uma classe, seu nome precisa ser registrado em uma tabela global. Então toda vez que algo é carregado, ele define uma classe e seu nome precisa ser registrado em uma tabela global.

A seguir, em C++ você deve ter ouvido falar do problema do frágil ivar, desculpe. A seguir, em c++ você deve ter ouvido falar do problema do frágil ivar, desculpe.

Problema de classe base frágil. Problema de classe base frágil.

Não temos esse problema com o ObjC porque um dos ajustes que fazemos é alterar os deslocamentos de todos os ivars dinamicamente, no momento do carregamento. ObjC não tem esse problema porque uma correção que fizemos foi alterar dinamicamente os deslocamentos de todos os ivars no carregamento.

A seguir, no ObjC você pode definir categorias que alteram os métodos de outra classe. A seguir, no ObjC, você pode definir categorias que alteram métodos de outra classe.

Às vezes, eles estão em classes que não estão na sua imagem em outro dylib, então esses ajustes de método devem ser aplicados neste ponto. Às vezes essas classes não estão na imagem de outro dylib e esses métodos devem ser aplicados naquele momento.

E, por último, ObjC [inaudível] é baseado em seletores únicos, portanto, precisamos de seletores únicos. Finalmente, ObjC [inaudível] é baseado em seletores únicos, portanto, precisamos de seletores únicos.

Então, agora que fizemos todos os ajustes de DADOS, agora podemos fazer todos os ajustes de DADOS que podem ser basicamente descritos estaticamente. Agora que fizemos todas as correções de dados, podemos fazer todas as correções de dados que podem ser basicamente descritas estaticamente.

Então agora é nossa chance de fazer correções dinâmicas de DADOS. Agora é hora de fazermos o reparo dinâmico de dados.

Então, em C++, você pode ter um inicializador, você pode dizer [inaudível] é igual a qualquer expressão que você quiser. Em C++, você pode ter um inicializador e dizer que [inaudível] é igual a qualquer expressão desejada.

Essa expressão arbitrária neste momento precisa ser executada e é executada neste momento agora. Esta expressão arbitrária, agora que precisa ser executada, foi executada.

Portanto, o compilador C++ gera inicializadores para essas inicializações arbitrárias de DADOS. O compilador C++ gera inicializadores para essas inicializações de dados arbitrárias.

No ObjC, existe algo chamado método +load. No ObjC, existe um método chamado +load.

Agora que o método +load está obsoleto, recomendamos que você não o use. O método +load agora está obsoleto e recomendamos que você não o use.

Recomendamos que você use uma inicialização positiva. Recomendamos que você use +inicialização.

Mas se você tiver um, ele será executado neste momento. Mas se você tiver um, ele será executado neste momento.

Então, agora eu tenho esse gráfico grande, temos seu executável principal top, todos os dylibs dependem, esse gráfico enorme, temos que rodar inicializadores. Agora que tenho esse gráfico grande, temos seu executável principal no topo do qual todos os dylibs dependem, esse gráfico grande, temos que executar o inicializador.

Em que ordem os queremos? Bem, nós os analisamos de baixo para cima. Em que ordem queremos que eles sejam organizados? Vamos contar de baixo para cima.

E a razão é que, quando uma inicialização é executada, pode ser necessário chamar algum dylib e você deseja ter certeza de que os dylibs já estão prontos para serem chamados. A razão é que quando um init é executado, pode ser necessário chamar alguns dylibs, e você precisa ter certeza de que os dylibs estão prontos para serem chamados.

Portanto, executando os inicializadores de baixo para cima na classe do aplicativo, você estará seguro para chamar algo de que depende. Portanto, executando o inicializador de baixo para cima, você pode chamar com segurança as coisas das quais depende.

Assim que todos os inicializadores estiverem concluídos, finalmente poderemos chamar o programa dyld principal. Depois que todas as rotinas de inicialização forem concluídas, podemos finalmente chamar o programa dyld principal

Então você sobreviveu a essa parte teórica, agora todos vocês são especialistas em como os processos iniciam, agora sabem que dyld é um programa auxiliar, ele carrega todas as bibliotecas dependentes, conserta todas as páginas DATA, executa inicializadores e depois salta para principal. Então você passou por esta parte teórica, agora todos vocês são especialistas em como os processos são iniciados e agora sabem que dyld é um programa auxiliar que carrega todas as bibliotecas dependentes, corrige todas as páginas de dados, executa o inicializador e depois pula para principal.

Então agora para colocar em prática toda essa teoria que você aprendeu, gostaria de passar a palavra ao Louis, que dará algumas dicas práticas. Agora, para colocar em prática a teoria que você aprendeu, gostaria de entregá-la ao Louis, que lhe dará alguns conselhos práticos.

Obrigado, Nick. Obrigado, Nick.

Todos nós já tivemos aquela experiência em que tiramos o telefone do bolso, pressionamos o botão home e tocamos no aplicativo que queremos executar. Todos nós já passamos por isso: tiramos o telefone do bolso, pressionamos o botão home e clicamos no aplicativo que queremos executar.

E então toque, toque e toque novamente em algum botão porque ele não está respondendo. Em seguida, clique, clique e clique em algum botão novamente porque ele não está respondendo.

Quando isso acontece comigo, é muito frustrante e quero excluir o aplicativo. Quando isso acontece comigo, fico muito frustrado e quero excluir o aplicativo.

Meu nome é Louis Gerbarg, trabalho no dyld e hoje vamos discutir como fazer seu aplicativo ser lançado instantaneamente, para que seus usuários fiquem encantados. Meu nome é Louis Gerbarg, trabalho na dyld e hoje vamos falar sobre como fazer seu aplicativo ser iniciado instantaneamente para que seus usuários fiquem felizes.Então, primeiro, vamos discutir o que iremos abordar nesta parte da palestra. Primeiro, vamos discutir esta parte.

Discutiremos a rapidez com que você realmente precisa lançar para que seus usuários tenham uma boa experiência. Discutiremos o quão rápido você realmente precisa para proporcionar uma boa experiência aos seus usuários.

Como medir esse tempo de lançamento. Como medir o tempo de lançamento.

Porque pode ser muito difícil. Porque é muito difícil.

As formas padrão de medir seu aplicativo não se aplicam antes que seu código possa ser executado. Até que o código possa ser executado, os métodos padrão de medição de um aplicativo não se aplicam.

Analisaremos uma lista dos motivos comuns pelos quais seu código ou, desculpe, examinaremos uma lista dos motivos comuns pelos quais seu lançamento pode ser lento. Listaremos alguns motivos comuns para explicar por que seu código inicia lentamente. Desculpe, listaremos alguns motivos comuns para explicar por que seu código inicia lentamente.

E, finalmente, vamos apresentar uma maneira de consertar todas as lentidão. Por fim, queremos falar sobre a solução para todos os problemas de lentidão.

Então vou dar um pequeno spoiler para o resto da minha palestra. Então, no resto do meu discurso, vou contar um pequeno episódio.

Você precisa fazer menos coisas [risos]. Você precisa fazer menos [risos].

Agora, não quero dizer que seu aplicativo deva ter menos recursos, estou dizendo que seu aplicativo precisa fazer menos coisas antes de ser executado. Agora, não estou dizendo que seu aplicativo deveria ter menos recursos, estou dizendo que seu aplicativo precisa fazer menos coisas antes de poder ser executado.

Queremos que você descubra como adiar alguns de seus comportamentos de inicialização para inicializá-los antes da execução. Esperamos que você consiga descobrir como atrasar alguns comportamentos de inicialização para que sejam inicializados antes da execução.

Então, vamos discutir os objetivos, quão rápido queremos lançar. Então, vamos falar sobre metas, com que rapidez queremos lançar.

Bem, o tempo de lançamento para várias plataformas é diferente. O tempo de inicialização é diferente para plataformas diferentes.

Mas, uma boa regra prática, 400 milissegundos é um bom tempo de lançamento. No entanto, uma boa regra é que 400 milissegundos é um bom tempo de inicialização.

Agora, a razão para isso é que lançamos animações no telefone para dar uma sensação de continuidade entre a tela inicial e o seu aplicativo, quando você o vê em execução. A razão para isso é que iniciamos a animação no telefone para dar uma sensação de continuidade quando você vê a tela inicial e seus aplicativos em execução.

E essas animações levam tempo, e essas animações dão a você a chance de ocultar seus tempos de lançamento. Essas animações levam tempo e oferecem a oportunidade de ocultar o tempo de inicialização.

Obviamente, isso pode ser diferente, em contextos diferentes, suas extensões de aplicativo também são aplicativos que precisam ser iniciados, eles são iniciados em diferentes períodos de tempo. Obviamente, isso pode ser diferente, em circunstâncias diferentes as extensões de seu aplicativo também são os aplicativos que precisam ser iniciados e são iniciados em momentos diferentes.

E um telefone, uma TV e um relógio são coisas diferentes, mas 400 milissegundos é uma boa meta. Celulares, TVs, relógios são coisas diferentes, mas 400 milissegundos é uma boa meta.

Você nunca pode demorar mais de 20 segundos para iniciar. O tempo de lançamento não pode exceder 20 segundos.

Se você demorar mais de 20 segundos, o sistema operacional encerrará seu aplicativo, presumindo que ele esteja passando por um loop infinito, e todos nós já tivemos essa experiência. Se você demorar mais de 20 segundos, o sistema encerrará seu aplicativo, presumindo que ele esteja passando por um loop infinito, todos nós já passamos por isso.

Quando você clica em um aplicativo, ele aparece na tela inicial, não responde e simplesmente desaparece, e geralmente é isso que acontece aqui. Quando você toca em um aplicativo, ele aparece na tela inicial, não responde e depois desaparece, o que geralmente acontece aqui.

Finalmente, é muito importante testar no seu dispositivo compatível mais lento. Finalmente, é importante testar no dispositivo compatível mais lento.

Portanto, esses temporizadores são valores constantes em todos os dispositivos suportados em nossas plataformas. Portanto, esses temporizadores são constantes para todos os dispositivos suportados na nossa plataforma.

Então, se você atingir 400 milissegundos em um iPhone 6S que está usando para testes agora, provavelmente você está atingindo por pouco, provavelmente não atingirá em um iPhone 5. Portanto, se você tocar por 400 milissegundos no iPhone 6S que está testando, poderá apenas tocar nele e talvez não no iPhone 5.

Então, vamos recapitular a parte de Nick na palestra. Vamos revisar o discurso de Nick.

O que precisamos fazer para iniciar, temos que analisar imagens, mapear imagens, rebase de imagens, vincular imagens, executar inicializadores de imagens e então chamar main. O que precisamos fazer para começar, precisamos analisar a imagem, mapear a imagem, redefinir a imagem, vincular a imagem, executar a inicialização da imagem e, em seguida, chamar main.

Se isso parece muito, é, estou exausto só de dizer isso. Se isso parece muito, é, e estou exausto só de dizer isso.

E depois disso, temos que chamar UIApplicationMain, você verá isso em seus aplicativos ObjC ou em seus aplicativos Swift tratados implicitamente. Em seguida, precisamos chamar UIApplicationMain, que você verá manipulado implicitamente em seu aplicativo ObjC ou aplicativo Swift.

Isso faz outras coisas, incluindo executar os inicializadores da estrutura e carregar seus nibs. Ele também pode fazer algumas outras coisas, incluindo executar inicializadores de estrutura e carregar nibs.

E finalmente você receberá uma chamada de volta no delegado do seu aplicativo. Finalmente, você receberá um retorno de chamada no delegado do aplicativo.

Estou mencionando esses dois últimos porque são contados nos tempos de 400 milissegundos que acabei de mencionar. Menciono os dois últimos porque são calculados usando os 400 milissegundos que acabei de mencionar.

Mas não vamos discuti-los nesta palestra. Mas não vamos discuti-los nesta palestra.Se você quiser ter uma visão melhor do que acontece por lá, há uma palestra de 2012, capacidade de resposta de desempenho de aplicativos iOS. Se você quiser entender melhor o que está acontecendo lá, há uma palestra de 2012, iOS App Performance Responsiveness.

Eu recomendo fortemente que você volte e veja o vídeo. Eu recomendo fortemente que você volte e assista ao vídeo.

Mas essa é a última coisa que falaremos deles agora. Mas esse é o último sobre o qual falaremos agora.

Então, vamos em frente, mais uma coisa que quero falar, lançamentos quentes versus lançamentos frios. Então, vamos passar para a outra coisa que quero dizer, emissão quente e emissão fria.

Então, quando você inicia um aplicativo, falamos sobre lançamentos quentes e frios. Ao iniciar uma aplicação, discutimos a partida a quente e a partida a frio.

E uma inicialização a quente é um aplicativo em que o aplicativo já está na memória, seja porque foi iniciado e encerrado anteriormente e ainda está no disco do kernel ou porque você acabou de copiá-lo. Embora uma inicialização a quente ocorra quando o aplicativo já está na memória porque foi iniciado e encerrado antes, ele ainda está no disco do kernel ou porque você acabou de copiá-lo.

Um lançamento a frio é um lançamento onde não está no disco. Uma inicialização a frio é uma inicialização que não está no disco.

E uma inicialização a frio é geralmente a mais importante de medir. A emissão de frio é frequentemente a medição mais importante.

A razão pela qual é mais importante medir uma inicialização a frio é quando o usuário está iniciando um aplicativo após reiniciar o telefone, ou pela primeira vez em muito tempo, é quando você realmente deseja que seja instantâneo. O motivo mais importante para uma inicialização a frio é que quando o usuário inicia o aplicativo após reiniciar o telefone, ou pela primeira vez em muito tempo, você realmente deseja que seja instantâneo.

Para medi-los, você realmente precisa reiniciar entre as medições. Para medi-los, você precisa reiniciar entre as medições.

Dito isto, se você está trabalhando para melhorar seus lançamentos quentes, seus lançamentos frios tenderão a melhorar também. Dito isto, se você estiver melhorando as partidas a quente, as partidas a frio também irão melhorar.

Você pode fazer ciclos rápidos de desenvolvimento em lançamentos quentes, mas de vez em quando, testar com lançamentos frios. Você pode executar ciclos de desenvolvimento rápidos em inicializações a quente, mas ocasionalmente usar inicializações a frio para testes.

Então, como medimos o tempo antes do main? Bem, temos um sistema de medição integrado no dyld, você pode acessá-lo definindo uma variável de ambiente. Então, como medimos o tempo antes do main? Temos um sistema de medição integrado no dyld, que você pode acessar definindo uma variável de ambiente.

DYLD Imprimir estatísticas. DYLD imprime dados.

E, na verdade, está disponível em sistemas operacionais de envio, mas imprime muitas informações de depuração interna que não são particularmente úteis; faltam algumas informações que você provavelmente deseja. Na verdade, já está disponível em sistemas operacionais lançados, mas imprime muitas informações de depuração interna que não são particularmente úteis e perde algumas das informações que você deseja.

E estamos consertando isso hoje. Estamos abordando esse assunto hoje.

Portanto, melhorou significativamente nos novos sistemas operacionais. Portanto, foi significativamente melhorado no novo sistema operacional.

Ele divulgará muito mais informações relevantes para você, que deverão fornecer maneiras práticas de melhorar seus tempos de lançamento. Ele fornecerá informações mais relevantes que fornecerão maneiras práticas de melhorar seu tempo de publicação.

E estará disponível na semente 2. Estará disponível na semente 2.

Então, outra coisa sobre a qual quero falar é que o depurador precisa pausar a inicialização em cada carregamento do dylib para analisar os símbolos do seu aplicativo e carregar seus pontos de interrupção, por meio de um cabo USB, o que pode consumir muito tempo. Então, outra coisa que eu diria é que o depurador precisa pausar a inicialização toda vez que o dylib é carregado para resolver símbolos no aplicativo e carregar pontos de interrupção por meio do cabo USB, o que pode consumir muito tempo.

Mas dyld sabe disso e subtrai o tempo limite do depurador dos números que está registrando. Mas o dyld sabe disso e subtrai o tempo do depurador do número registrado.

Então você não precisa se preocupar com isso, mas você percebe porque dyld lhe dará números muito menores do que você observaria olhando o relógio na parede. Então você não precisa se preocupar com isso, mas você notará porque dyld lhe dará um número muito menor do que você veria se olhasse o relógio na parede.

Isso é esperado e compreendido, e tudo está indo bem se você perceber isso, mas eu só queria anotar isso. Isso é esperado e compreensível, e se você ver, é tudo normal, mas eu só queria anotar.

Então, vamos prosseguir, para definir uma variável de ambiente no Xcode, basta ir ao editor de esquema e adicioná-la assim. Vamos definir uma variável de ambiente no Xcode, basta ir ao editor de esquema e adicioná-la assim.

Depois de fazer isso, você obterá o novo log do console na saída, saída do console registrada. Depois de fazer isso, você obterá o novo log do console para saída, log de saída do console.

E como é isso? Bem, esta é a aparência da saída, e temos uma barra de tempo na parte inferior representando as diferentes partes dela. Como é isso? Esta é a aparência da saída, com uma barra de tempo na parte inferior para representar as diferentes partes dela.

E vamos acrescentar mais uma coisa. Vamos adicionar mais uma coisa.

Vamos adicionar um indicador para a meta de 400 milissegundos, que este aplicativo em que estou trabalhando não está atingindo. Vamos adicionar um indicador para a meta de 400 milissegundos, que não está sendo atingida com este aplicativo que estou usando.

Então, se você olhar, essas são basicamente as etapas que Nick discutiu para iniciar um aplicativo, então vamos percorrê-las em ordem. Se você observar isso, verá que são basicamente as etapas que Nick discutiu sobre como iniciar um aplicativo. Vamos examiná-los em ordem.Portanto, o carregamento de dylib, a grande coisa a entender sobre o carregamento de dylib e a lentidão que você verá nele, é que dylibs incorporados podem ser caros. Portanto, o carregamento de dylib, uma questão importante para entender o carregamento de dylib, e a lentidão que você verá, é que dylibs incorporados podem ser caros.

Então Nick disse que um aplicativo médio pode ter de 100 a 400 dylibs. Nick disse que um aplicativo pode ter em média de 100 a 400 dylibs.

Mas os dylibs do sistema operacional são rápidos porque, quando construímos o sistema operacional, temos maneiras de pré-calcular muitos desses dados. Mas os dylibs do sistema operacional são rápidos porque, quando construímos um sistema operacional, temos maneiras de pré-calcular grandes quantidades de dados.

Mas não temos todos os dylib em todos os aplicativos quando estamos construindo o sistema operacional. Mas ao construir um sistema operacional, nem todo aplicativo contém dylibs.

Não podemos pré-calculá-los para os dylibs que você incorpora ao seu aplicativo, então temos que passar por um processo muito mais lento enquanto os carregamos. Não podemos pré-calculá-los para dylibs incorporados na aplicação, portanto, ao carregá-los, temos que passar por um processo muito mais lento.

E a solução para isso é que só precisamos usar menos dylibs e isso pode ser difícil. A solução para esse problema é que só precisamos usar menos dylibs, o que pode ser grosseiro.

E não estou dizendo que você não pode usar nenhum, mas há algumas opções aqui nas quais você pode mesclar dylibs existentes. Não estou dizendo que você não pode usar nenhum, mas aqui estão duas opções que você pode usar para mesclar dylibs existentes.

Você pode usar arquivos estáticos e vinculá-los a ambos, em aplicativos dessa forma. Você pode usar arquivos estáticos e vinculá-los aos dois aplicativos.

E você tem a opção de carregamento lento, que é usar o dlopen, mas o dlopen causa alguns problemas sutis de desempenho e correção e, na verdade, resulta na realização de mais trabalho posteriormente, mas é adiado. Você pode escolher o carregamento lento, mesmo usando o dlopen, mas o dlopen causa alguns problemas sutis de desempenho e correção; na verdade, faz com que mais trabalho seja feito posteriormente, mas está atrasado.

Portanto, é uma opção viável, mas você deve pensar muito sobre isso e eu desencorajaria isso, se possível. Então, é uma opção viável, mas você deveria pensar nisso e eu o dissuadiria, se possível.

Então, eu tenho um aplicativo aqui que atualmente tem 26 dylibs, e está levando 240 milissegundos apenas para carregá-los, mas se eu mudar e mesclar esses dylibs em dois dylibs, levará apenas 20 milissegundos para carregar os dylibs. Eu tenho um aplicativo que atualmente possui 26 dylibs e leva 240 ms para carregá-los, mas se eu alterá-lo e mesclar esses dylibs em dois dylibs, leva apenas 20 ms para carregá-los.

Portanto, ainda posso ter dylibs, ainda posso usá-los para compartilhar funcionalidades entre meu aplicativo e minha extensão, mas limitá-los será muito útil. Portanto, ainda posso usar dylibs, ainda posso usá-los para compartilhar funcionalidades entre meu aplicativo e minhas extensões, porém, limitá-los seria muito útil.

E entendo que isso é uma troca que você está fazendo entre a conveniência do desenvolvimento e o tempo de inicialização do aplicativo para os usuários. Entendo que esta é uma troca que você faz entre a conveniência de desenvolvimento para seus usuários e o tempo de inicialização do aplicativo.

Porque quanto mais dylibs você tiver, mais fácil será construir e vincular novamente seu aplicativo e mais rápidos serão seus ciclos de desenvolvimento. Porque quanto mais dylibs houver, mais fácil será construir e vincular novamente o aplicativo e mais rápido será o ciclo de desenvolvimento.

Então você absolutamente pode e deve usar alguns, mas é bom tentar atingir um número limitado, nós diríamos, eu diria de improviso, um bom alvo é cerca de meia dúzia. Portanto, você pode e deve usar alguns, mas é melhor atingir um número limitado e, eu diria, um bom alvo seria cerca de seis.

Agora que corrigimos nossa contagem de dylib, vamos passar para o próximo local onde estamos tendo uma desaceleração. Agora que resolvemos o problema da contagem de dylib, vamos passar para a próxima desaceleração.

Entre 350 milissegundos em vinculação e rebase. 350 milissegundos entre a ligação e a realocação.

Então, como Nick mencionou, o rebase tende a ser mais lento devido ao iO e a ligação tende a ser computacionalmente cara, mas o iO já foi feito. Como Nick mencionou, o rebase será mais lento devido ao iO e o custo computacional da ligação será maior, mas isso é feito com o iO.

Então esse iO é para ambos e eles estão se misturando, o momento também está se misturando. Então o iO foi para os dois, eles vieram e chegou a hora.

Então, se entrarmos e olharmos para isso, tudo isso está corrigindo ponteiros na seção DADOS. Se entrarmos e olharmos, tudo isso são ponteiros para a seção de dados fixos.

Então o que temos que fazer é consertar menos dicas. Então o que precisamos fazer é corrigir menos indicadores.

Nick mostrou uma ferramenta que você pode executar para ver quais indicadores estão sendo corrigidos na seção DADOS, informações do dyld. Nick mostra uma ferramenta que você pode executar para ver quais ponteiros estão sendo corrigidos em DATA, seção, informações dyld.

E mostra em quais segmentos e seções as coisas estão, para que você tenha uma boa ideia do que está sendo consertado. Mostra partes e pedaços de coisas, o que dá uma boa ideia do que está sendo restaurado.

Por exemplo, se você vir um símbolo para uma classe ObjC na seção ObjC, provavelmente você tem várias classes ObjC. Por exemplo, se você vir símbolos para classes ObjC na seção ObjC, provavelmente terá várias classes ObjC.

Portanto, uma das coisas que você pode fazer é simplesmente reduzir o número de objetos de classes ObjC e ivars que você possui. Uma coisa que você pode fazer é reduzir o número de objetos da classe ObjC e ivars que você possui.

Portanto, há vários estilos de codificação que incentivam classes muito pequenas, que talvez tenham apenas uma ou duas funções. Portanto, existem muitos estilos de codificação que incentivam classes muito pequenas, que podem ter apenas uma ou duas funções.E esses padrões específicos podem resultar em lentidão gradual de seus aplicativos à medida que você adiciona cada vez mais deles. E, à medida que você adiciona mais e mais aplicativos, esses padrões específicos podem fazer com que seus aplicativos fiquem gradualmente mais lentos.

Portanto, você deve ter cuidado com isso. Portanto, você deve ter cuidado com isso.

Agora, ter 100 ou 1.000 aulas não é um problema, mas vimos aplicativos com 5, 10, 15, 20.000 aulas. Agora ter 100 ou 1000 turmas não é problema, mas temos visto aplicações com 5, 10, 15, 20 mil turmas.

E nesses casos isso pode adicionar até 7 ou 800 milissegundos ao tempo de inicialização para o kernel paginá-los. Nestes casos, o tempo de inicialização para o kernel paginá-los aumentará em 7 ou 800 milissegundos.

Outra coisa que você pode fazer é tentar reduzir o uso de funções virtuais C++. Outra coisa que você pode fazer é minimizar o uso de funções virtuais C++.

Portanto, as funções virtuais criam o que chamamos de tabelas V, que são iguais aos metadados ObjC, no sentido de que criam estruturas na seção DATA que precisam ser corrigidas. Portanto, as funções virtuais criam o que chamamos de tabelas V, que são iguais aos metadados ObjC porque criam estruturas na parte dos dados que precisam ser corrigidas.

Eles são menores que o ObjC, são menores que os metadados do ObjC, mas ainda são significativos para alguns aplicativos. Eles são menores que o ObjC e menores que os metadados do ObjC, mas ainda são importantes para algumas aplicações.

Você pode usar estruturas Swift. Estruturas Swift podem ser usadas.

Portanto, o Swift tende a usar menos dados que contenham dicas para ajustes desse tipo. Portanto, o Swift tende a usar menos dados que contenham indicadores para tais correções.

E o Swift é mais inlinável e pode co-gerar melhor para evitar muito disso, então migrar para o Swift é uma ótima maneira de melhorar isso. Além disso, o Swift é mais fácil de incorporar e funciona melhor em conjunto para evitar isso, então mudar para o Swift é uma ótima maneira de melhorar.

E outra coisa, você deve ter cuidado com códigos gerados por máquina, então temos casos em que você pode descrever algumas estruturas em termos de uma DSL ou alguma linguagem customizada e então ter um programa que gere outro código a partir dele. Outra coisa, você deve ter cuidado com o código gerado por máquina, por isso temos exemplos onde você descreve alguma estrutura em uma DSL ou linguagem customizada e depois faz um programa gerar outro código a partir dela.

E se esses programas gerados tiverem muitos ponteiros, eles podem se tornar muito caros porque quando você gera seu código você pode gerar estruturas muito, muito grandes. Se esses programas gerados contiverem muitos ponteiros, eles poderão se tornar muito caros porque quando você gera código você pode gerar estruturas muito, muito grandes.

Vimos casos em que isso causa megabytes e megabytes de dados. Vimos que isso pode resultar em megabytes de dados.

Mas a vantagem é que você geralmente tem muito controle porque você pode simplesmente alterar o gerador de código para usar algo que não seja ponteiro, por exemplo, estruturas baseadas em deslocamento. Mas a vantagem é que você geralmente tem muito controle, pois pode alterar o gerador de código para usar algo que não seja um ponteiro, como uma estrutura baseada em deslocamento.

E isso será uma grande vitória. Esta será uma grande vitória.

Então nesse caso vamos ver o que está acontecendo aqui comigo, com meu tempo de carregamento. Nesse caso, vamos ver o que está acontecendo aqui, tempo de carregamento.

E eu tenho pelo menos 10.000 aulas, na verdade tenho 20.000, tantas que saiu do slide. Tenho pelo menos 10.000 cursos, na verdade tenho 20.000 cursos, muitos deles acabaram de sair dos slides.

E se eu reduzir para 1.000 aulas, apenas reduzo meus tempos de lançamento, meu tempo nesta parte do lançamento de 350 para 20 milissegundos. Se eu reduzir para 1000 aulas reduzo meu tempo de inicialização, passo de 350ms para 20ms nessa parte.

Então, agora, tudo, exceto o inicializador, está abaixo da marca de 400 milissegundos, então estamos indo muito bem. Agora, exceto o inicializador, todo o resto está abaixo de 400 ms e estamos indo muito bem.

Então, para a configuração do ObjC, bem, Nick mencionou tudo o que precisava ser feito. Para a criação do ObjC, Nick mencionou tudo o que ele precisava fazer.

Teve que fazer cadastro de classe, tem que lidar com os ivars não frágeis, tem que fazer cadastro de categoria e tem que fazer seletor uniqing. Tem que fazer registro de classe, tem que lidar com ivars não friáveis, tem que fazer registro de classe e tem que fazer exclusividade do seletor.

E não vou gastar muito tempo nisso, e a razão pela qual não vou é que resolvemos tudo isso corrigindo o rebase e os dados, e vinculando antes. Não vou gastar muito tempo com isso, e a razão pela qual não vou gastar muito tempo com isso é que resolvemos todos esses problemas restabelecendo a base e os dados, bem como as ligações anteriores.

Todas as reduções serão a mesma coisa que você deseja fazer aqui. Todas as reduções aqui são iguais.

Então conseguimos uma pequena vitória grátis aqui, é pequena. Então conseguimos uma pequena vitória grátis aqui, é pequena.

São 8 milissegundos. Isso é 8 milissegundos.

Mas não fizemos nada explícito para isso. Mas não fizemos nada explícito.

E agora, finalmente, veremos meus inicializadores, que são os grandes 10 segundos aqui. Finalmente, chegamos aos meus inicializadores e eles são os 10 segundos mais importantes aqui.

Então, vou me aprofundar um pouco mais nisso do que Nick. Então, vou um pouco mais fundo do que Nick.

Existem dois tipos de inicializadores, inicializadores explícitos, coisas como +load. Existem dois tipos de inicializadores, inicializadores explícitos como +load.

Como Nick disse, recomendamos substituir isso por +initialize, o que fará com que o tempo de execução do ObjC inicialize seu código quando as classes forem substanciadas, em vez de quando o arquivo for carregado. Como Nick disse, recomendamos substituí-lo por +initialize, o que fará com que o tempo de execução do ObjC inicialize o código quando a classe for confirmada, em vez de quando o arquivo for carregado.Ou, em C/C++, há um atributo que pode ser colocado em funções que fará com que elas sejam geradas como inicializadores, então esse é um inicializador explícito, que preferimos que você não use. Alternativamente, em C/C++, existe um atributo que você pode colocar em uma função que irá gerar esses inicializadores, que é um inicializador explícito e esperamos que você não o use.

Preferimos que você os substitua por inicializadores de site de chamada. Preferimos que você os substitua por inicializadores de site de chamada.

Então, por inicializadores de site de chamada, quero dizer coisas como despachar uma vez. Ao chamar o inicializador do site, quero dizer algo como despachá-lo uma vez.

Ou se você estiver em código de plataforma cruzada, faça pthread uma vez. Alternativamente, se você estiver usando código multiplataforma, use pthread uma vez.

Ou se você estiver em código C++, std uma vez. Ou se você estiver em código C++, std uma vez.

Todas essas funções possuem basicamente o mesmo tipo de funcionalidade onde, qualquer código em um desses blocos será executado na primeira vez que for atingido e somente isso. Todas essas funções possuem basicamente a mesma funcionalidade, qualquer código dentro de um bloco será executado no primeiro hit e pronto.

O envio único é muito, muito otimizado em nosso sistema. Agendar uma vez é muito, muito otimizado em nosso sistema.

Após a primeira execução dele, é basicamente equivalente a uma operação não executada, então eu recomendo fortemente que, em vez de usar inicializadores explícitos. Após a primeira execução, é basicamente equivalente ao não-op executado sobre ele, por isso não recomendo fortemente o uso de inicializadores explícitos.

Então, vamos passar para os inicializadores implícitos. Vamos continuar falando sobre inicializadores implícitos.

Portanto, inicializadores implícitos são o que Nick descreveu principalmente em globais C++ com inicializadores não triviais, com construtores não triviais. Portanto, inicializadores de aplicativos são descritos por Nick em variáveis ​​globais c++, que incluem inicializadores não triviais e construtores não triviais.

E uma opção é substituí-los por inicializadores de site de chamada, como acabamos de mencionar. Uma opção é substituí-los pelos inicializadores de site de chamada que acabamos de mencionar.

Certamente há lugares onde você pode colocar globais com estruturas não globais ou ponteiros para objetos que você inicializará. É claro que você pode colocar variáveis ​​globais com estruturas não globais em algum lugar, ou ponteiros para objetos a serem inicializados.

Outra opção é que você não tenha inicializadores não triviais. Outra opção é que você não tenha um inicializador não trivial.

Portanto, em C++ existem inicializadores chamados POD, dados simples e antigos. Em c++ existe um inicializador chamado POD, um dado simples e antigo.

E se seus objetos são apenas dados antigos, o vinculador estático ou estático irá pré-calcular todos os dados para a seção DATA, exibi-los como apenas dados vistos lá, não precisa ser executado, não precisa ser consertado. Se seus objetos forem apenas dados antigos, estáticos ou estáticos, o vinculador irá pré-calcular todos os dados na seção de dados, como os dados que você vê aqui, eles não precisam ser executados e não precisam ser corrigidos.

Finalmente, pode ser muito difícil encontrá-los, porque estão implícitos, mas temos um aviso no compilador -Wglobal-constructors e se você fizer isso, ele lhe dará avisos sempre que você estiver gerando um deles. Finalmente, é difícil encontrá-los porque estão implícitos, mas temos um aviso no compilador-wglobal-constructor que lhe dará um aviso se você gerar um deles.

Portanto, é bom adicionar isso aos sinalizadores que seu compilador usa. Portanto, é melhor adicioná-lo aos sinalizadores usados ​​pelo compilador.

Outra opção é apenas reescrevê-los em Swift. Outra opção é reescrevê-los rapidamente.

E a razão é que o Swift tem variáveis ​​globais e elas serão inicializadas, é garantido que serão inicializadas antes de você usá-las. A razão é que o Swift possui variáveis ​​globais que são inicializadas e é garantido que serão inicializadas antes de você usá-las.

Mas a forma como isso acontece é, em vez de usar um inicializador, ele, nos bastidores, usa o despacho uma vez para você. Mas a forma como é implementado é que, nos bastidores, em vez de usar um inicializador, ele usa um despacho para você.

Ele usa um desses inicializadores de site de chamada. Ele usa um dos inicializadores de site de chamada.

Então, mudar para o Swift cuidará disso para você, então eu recomendo fortemente que seja uma opção. Portanto, mudar para o Swift irá ajudá-lo a resolver esse problema, por isso recomendo fortemente que você faça isso como uma opção.

Finalmente, em seus inicializadores, por favor, não chame dlopen, isso será um grande impacto no desempenho por vários motivos. Finalmente, no seu inicializador, não chame dlopen, isso será um grande impacto no desempenho por vários motivos.

Quando o dyld está em execução, é antes do aplicativo ser iniciado e podemos fazer coisas como desligar o bloqueio, porque somos de thread único. Quando o dyld está em execução, ele ainda não foi iniciado, podemos desligar o bloqueio porque somos de thread único.

Assim que o dlopens aconteceu, nessas situações, o gráfico de como nossos inicializadores devem executar muda, podemos ter vários threads, temos que ativar o bloqueio, só vai ser uma grande bagunça de desempenho. Uma vez que acontece o dlopen, nesses casos, como o inicializador executa o gráfico alterado, podemos ter vários threads e ter que abrir o bloqueio, o que será uma grande bagunça de desempenho.

Você também pode ter impasses sutis e comportamentos indefinidos. Você também pode ter impasses sutis e comportamento indefinido.

Além disso, não inicie threads em seus inicializadores, basicamente pelo mesmo motivo. Além disso, não inicie threads em inicializadores, basicamente pelo mesmo motivo.

Você pode configurar um texto mudo, se necessário, e o texto mudo ainda tem, como os textos mudos preferidos, que têm valores estáticos predefinidos com os quais você pode configurá-los sem execução de código. Você pode definir um texto silencioso, se necessário, texto silencioso, e há até mesmo texto silencioso preferido, valores estáticos predefinidos que você pode definir sem executar código.Mas, na verdade, iniciar um thread em seu inicializador é potencialmente um grande problema de desempenho e correção. Mas, na verdade, iniciar um thread em um inicializador é um problema potencial de desempenho e correção.

Então aqui temos algum código, eu tenho uma classe C++ com um inicializador não trivial. Aqui temos algum código, eu tenho uma classe c++ que possui um inicializador importante.

Estou tendo problemas com a conexão. Há um problema com minha conexão.

Por favor, tente novamente em alguns instantes. Por favor, tente novamente mais tarde.

Bem, obrigado Siri. Obrigado, Siri.

Estou tendo um inicializador não trivial. Eu tenho um inicializador não trivial.

E acho que consegui depurar tudo comentado e tudo bem, estou com 50 milissegundos no total. Acho que depurei tudo comentado e são apenas 50ms no total.

Tenho muito tempo para inicializar meus nibs e fazer todo o resto, estamos em muito boa forma. Tive tempo suficiente para inicializar a ponta e fazer outras coisas e estávamos em muito boa forma.

Agora que já passamos por isso, vamos falar sobre o que deveríamos saber se você simplesmente fosse muito longo e bastante denso. Agora que já cobrimos isso, vamos falar sobre o que devemos saber se você for apenas, este é muito longo e denso.

A primeira é usar estatísticas de impressão dyld para medir seus tempos, adicioná-las aos seus conjuntos de desempenho ou agressão. A primeira é usar dyld para imprimir estatísticas para medir seus tempos, adicione isso ao seu desempenho ou conjunto de ataques.

Assim, você pode acompanhar o desempenho do seu aplicativo ao longo do tempo, de modo que, enquanto estiver fazendo algo ativamente, você não o encontrará meses depois e terá problemas para depurá-lo. Assim, você pode acompanhar o desempenho do seu aplicativo ao longo do tempo. Enquanto estiver trabalhando ativamente em algo, você o perderá meses depois e será difícil depurar.

Você pode melhorar o tempo de inicialização do seu aplicativo reduzindo o número de dylibs que possui, reduzindo a quantidade de classes ObjC que possui e eliminando seus inicializadores estáticos. Você pode melhorar o tempo de inicialização do seu aplicativo reduzindo o número de dylibs, reduzindo o número de classes ObjC e eliminando inicializadores estáticos.

E você pode melhorar em geral usando mais Swift porque ele faz as coisas certas. Freqüentemente, você pode melhorar usando velocidades mais rápidas porque é a coisa certa a fazer.

Finalmente, o uso do dlopen é desencorajado, pois causa problemas sutis de desempenho que são difíceis de diagnosticar. Finalmente, o uso do dlopen é desencorajado e pode causar problemas sutis de desempenho que são difíceis de diagnosticar.

Para mais informações você pode ver o URL na tela. Veja o URL na tela para mais informações.

Há várias sessões relacionadas no final da semana e, novamente, há a sessão de desempenho do aplicativo de 2012 que aborda outras partes do lançamento do aplicativo, que recomendo fortemente que você assista, se estiver interessado. Haverá algumas sessões relacionadas ainda esta semana. A sessão de desempenho de aplicativos de 2012 cobrirá outras partes da publicação de aplicativos e é altamente recomendada se você estiver interessado.

Obrigado por terem vindo a todos, tenham uma ótima semana. Obrigado a todos por terem vindo e tenham uma ótima semana.

FAQ

What to read next

Related

Continue reading