Optimización del tiempo de inicio de la aplicación
Optimizar el tiempo de inicio de la aplicación
optimizar el tiempo de inicio de la aplicación
https://developer.apple.com/videos/play/wwdc2016/406/
[ Música ] Buenos días y bienvenidos a la sesión 406, Optimización del tiempo de inicio de la aplicación. [Música] Buenos días a todos y bienvenidos a la Conferencia 406: Optimización del tiempo de inicio de la aplicación.
Mi nombre es Nick Kledzik y hoy mi colega Louis y yo los llevaremos a realizar una visita guiada sobre cómo se inicia un proceso. Mi nombre es Nick Kledzik y hoy mi colega Louis y yo les mostraremos cómo se inicia un proceso.
Ahora quizás te preguntes si este tema es adecuado para mí. Ahora quizás estés pensando, ¿este tema es adecuado para mí?
Así que hicimos que nuestro equipo de marketing de desarrollo de crack investigara un poco y determinaron que hay tres grupos que se beneficiarán al escuchar esta charla. Así que hicimos que nuestro increíble equipo de marketing investigara un poco y determinaron que había tres grupos de personas que se beneficiarían al escuchar esta charla.
El primero son los desarrolladores de aplicaciones que tienen una aplicación que se inicia muy lentamente. El primero es un desarrollador de aplicaciones cuya aplicación tarda en iniciarse.
El segundo grupo son los desarrolladores de aplicaciones que no quieren estar en el primer grupo [risas]. El segundo grupo son los desarrolladores de aplicaciones que no quieren estar en el primer grupo [risas].
Y, por último, cualquiera que tenga mucha curiosidad sobre cómo funciona el sistema operativo. Por último, ¿quién siente curiosidad por saber cómo funciona un sistema operativo?
Entonces esta charla se va a dividir en dos secciones, la primera es más teórica y la segunda más práctica, yo haré la primera parte teórica. Entonces esta charla se dividirá en dos partes, la primera parte es más teórica y la segunda parte es más práctica, hablaré de la primera parte.
Y en él lo guiaré a través de todos los pasos que suceden, hasta llegar al principal. Voy a guiarte a través de todos los pasos que suceden, hasta llegar al cuerpo principal.
Pero para que entiendas y aprecies todos los pasos, primero necesito darte un curso intensivo sobre Mach-O y memoria virtual. Pero para que lo entiendas y lo aprecies primero necesito darte un curso intensivo sobre computación analógica y memoria virtual.
Primero, algo de terminología Mach-O, rápidamente. Primero, algo de terminología Mach-O.
Mach-O es un conjunto de tipos de archivos para diferentes ejecutables en tiempo de ejecución. Mach-O es un conjunto de tipos de archivos para diferentes ejecutables en tiempo de ejecución.
Entonces, el primer ejecutable, que es el binario principal de una aplicación, también es el binario principal de una extensión de aplicación. El primer archivo ejecutable es el archivo binario principal de la aplicación y el archivo binario principal de la extensión de la aplicación.
Un dylib es una biblioteca dinámica, que en otras plataformas se encuentra, es posible que las conozca como DSO o DLL. Un dylib es una biblioteca dinámica y, en otras plataformas, es posible que la conozca como DSO o dll.
Nuestra plataforma también tiene otro tipo de cosa llamada paquete. Nuestra plataforma también tiene otra cosa llamada paquete.
Ahora bien, un paquete es un tipo especial de dylib al que no se puede vincular, todo lo que puede hacer es cargarlo en tiempo de ejecución mediante un dlopen y se usa en Mac OS para complementos. Un paquete es un dylib especial al que no puedes vincular, todo lo que puedes hacer es cargarlo en tiempo de ejecución a través de dlopen, que se usa para complementos en Mac OS.
Por último, está el término imagen. Finalmente hay imágenes.
Imagen se refiere a cualquiera de estos tres tipos. Imagen se refiere a cualquiera de estos tres tipos.
Y usaré mucho ese término. Usaré mucho esta palabra.
Y, por último, el término marco está muy sobrecargado en nuestra industria, pero en este contexto, un marco es un dylib con una estructura de directorio especial a su alrededor para contener los archivos que necesita ese dylib. Finalmente, el término marco está muy sobrecargado en nuestra industria, pero en este contexto, un marco es un dylib que tiene una estructura de directorio especial a su alrededor para contener los archivos que ese dylib necesita.
Así que profundicemos en el formato de imagen Mach-O. Saltemos directamente al formato de imagen Mach-O.
Una imagen Mach-O se divide en segmentos; por convención, todos los nombres de segmentos usan letras mayúsculas. Una imagen Mach-O se divide en segmentos y, por convención, todos los nombres de los segmentos están en letras mayúsculas.
Ahora, cada segmento es siempre un múltiplo del tamaño de la página, en este ejemplo el texto es de 3 páginas, DATA y LINKEDIT son cada uno de una página. Ahora, cada segmento es siempre un múltiplo del tamaño de la página; en este ejemplo, el texto es de 3 páginas y los datos y LINKEDIT son ambos de 1 página.
Ahora el tamaño de la página está determinado por el hardware, para arm64, el tamaño de la página es 16K, todo lo demás es 4k. Ahora el tamaño de la página lo determina el hardware, para arm64 el tamaño de la página es 16K, otros son 4k.
Ahora, otra forma de ver las cosas son las secciones. Otro enfoque es la segmentación.
Entonces las secciones son algo que el compilador omite. Por lo tanto, el compilador ignora parte de esto.
Pero las secciones son en realidad solo un subrango de un segmento, no tienen ninguna de las restricciones de tamaño de página, pero no se superponen. Pero la sección es en realidad sólo un subrango de un segmento. No tienen límite de tamaño de página, pero no se superponen.
Ahora, los nombres de segmentos más comunes son TEXTO, DATOS, LINKEDIT; de hecho, casi todos los binarios tienen exactamente esos tres segmentos. Hoy en día, los nombres de segmentos más comunes son TEXT, DATA y LINKEDIT. De hecho, casi todos los binarios tienen estos tres segmentos.
Puede agregar otros personalizados, pero generalmente no agrega ningún valor. Puede agregar valores personalizados, pero normalmente no se agregarán valores.
Entonces, ¿para qué se utilizan? Bueno, el TEXTO está al comienzo del archivo, contiene el encabezado Mach, contiene instrucciones de la máquina y cualquier constante de solo lectura, como cadenas c. ¿Para qué son estos? El texto está al principio del archivo y contiene el encabezado Mach, que contiene las instrucciones de la máquina, así como constantes de solo lectura, como cadenas c.
El segmento de DATOS se reescribe, el segmento de DATOS contiene todas sus variables globales. El segmento de datos se reescribe y contiene todas las variables globales.
Y por último, está el LINKEDIT. Finalmente, LINKEDIT.Ahora el LINKEDIT no contiene sus funciones de variables globales, un LINKEDIT contiene información sobre su función de variables como su nombre y dirección. LINKEDIT no contiene funciones de variables globales, contiene información sobre funciones de variables, como sus nombres y direcciones.
Seguramente también habrás oído hablar de las limas universales, ¿qué son? Bueno, supongamos que creas una aplicación iOS, para 64 bits, y ahora tienes este archivo Mach-O, entonces, ¿qué sucede con el siguiente código cuando dices que también quieres compilarlo para dispositivos de 32 bits? Cuando reconstruyas, Xcode creará otro archivo Mach-O separado, este creado para 32 bits, RB7. Seguramente también habrás oído hablar de las limas universales, ¿qué son? Digamos que creó una aplicación iOS para 64 bits y ahora tiene este archivo Mach-O, entonces, ¿qué sucede después cuando dice que desea crearla también para dispositivos de 32 bits? Cuando reconstruya, Xcode creará otro archivo Mach-O separado, este creado para RB7 de 32 bits.
Y luego esos dos archivos se fusionan en un tercer archivo, llamado archivo universal Mach-O. Luego, estos dos archivos se fusionan en un tercer archivo llamado archivo universal Mach-O.
Y eso tiene un encabezado al principio, y todo el encabezado tiene una lista de todas las arquitecturas y cuáles son sus compensaciones en el archivo. Tiene un encabezado al principio con una lista de todas las arquitecturas y sus compensaciones en el archivo.
Y ese encabezado también tiene el tamaño de una página. El título también tiene el tamaño de una página.
Ahora quizás se pregunte, ¿por qué los segmentos tienen varios tamaños de página? ¿Por qué el encabezado tiene el tamaño de una página y está desperdiciando mucho espacio? Ahora quizás se pregunte, ¿por qué los segmentos tienen varios tamaños de página? ¿Por qué los encabezados tienen el tamaño de una página? Se desperdicia mucho espacio.
Bueno, la razón por la que todo está basado en páginas tiene que ver con nuestro próximo tema, que es la memoria virtual. La razón por la que todo está basado en páginas se relaciona con nuestro siguiente tema y es la memoria virtual.
Entonces, ¿qué es la memoria virtual? Algunos de ustedes quizás conozcan el dicho en ingeniería de software de que cada problema se puede resolver agregando un nivel de direccionamiento indirecto. Entonces, ¿qué es la memoria virtual? Algunos de ustedes quizás conozcan el dicho en ingeniería de software de que cada problema se puede resolver agregando un nivel de direccionamiento indirecto.
Entonces, el problema que resuelve la memoria virtual es ¿cómo administras toda tu RAM física cuando tienes todos estos procesos? Entonces agregaron un poco de indirección. Entonces, el problema que resuelve la memoria virtual es: ¿cómo se administra toda la RAM física cuando se tienen todos estos procesos? Entonces agregan algo de indirección.
Cada proceso es un espacio de direcciones lógicas que se asigna a alguna página física de RAM. Cada proceso es un espacio de direcciones lógicas, que se asigna a una determinada página física de RAM.
Ahora bien, esta asignación no tiene que ser uno a uno, podría tener direcciones lógicas que no vayan a ninguna RAM física y puede tener múltiples direcciones lógicas que vayan a la misma RAM física. Ahora, esta asignación no tiene que ser uno a uno, puede tener direcciones lógicas que no vayan a la RAM física, o puede tener múltiples direcciones lógicas que vayan a la misma RAM física.
Esto ofreció muchas oportunidades aquí. Esto ofrece muchas oportunidades.
Entonces, ¿qué puedes hacer con VM? Bueno, primero, si tienes una dirección lógica que no se asigna a ninguna RAM física, cuando accedes a esa dirección en tu proceso, ocurre una falla de página. Entonces, ¿qué puede hacer una máquina virtual? Primero, si hay una dirección lógica que no está asignada a ninguna RAM física y cuando accede a esa dirección en un proceso, se producirá un error de página.
En ese momento, el núcleo detiene ese hilo e intenta descubrir qué debe suceder. En este punto, el núcleo detiene el hilo e intenta descubrir qué debe suceder.
Lo siguiente es que si tiene dos procesos, con diferentes direcciones lógicas, asignados a la misma página física, esos dos procesos ahora compartirán el mismo bit de RAM. A continuación, si tiene dos procesos con diferentes direcciones lógicas, asignados a la misma página física, ambos procesos ahora comparten los mismos bits de RAM.
Ahora puede compartir entre procesos. Ahora puede compartir entre procesos.
Otra característica interesante es el mapeo respaldado por archivos. Otra característica interesante es el mapeo de soporte de archivos.
En lugar de leer un archivo completo en la RAM, puede decirle al sistema VM a través de la llamada mmap que quiero que esta porción de este archivo se asigne a este rango de direcciones en mi proceso. Puede decirle al sistema VM a través de la llamada mmap que en lugar de leer el archivo completo en la RAM, quiero que esta parte del archivo se asigne a este rango de direcciones en el proceso.
Entonces, ¿por qué harías eso? Bueno, en lugar de tener que leer el archivo completo, al configurar ese mapeo, cuando accede por primera vez a esas diferentes direcciones, como si lo hubiera leído en la memoria, cada vez que accede a una dirección a la que no se ha accedido antes causará una falla de página, el kernel leerá solo esa página. Entonces, ¿por qué harías eso? En lugar de tener que leer el archivo completo, configurado por el mapa, cuando accede por primera vez a estas diferentes direcciones, si lo lee en la memoria, cada vez que accede a una dirección a la que no se ha accedido antes, provocará un error de página y el kernel leerá una página.
Y eso le da una lectura perezosa de su archivo. Esto le dará pereza para leer su documento.
Ahora podemos juntar todas estas características, y lo que les dije sobre Mach-O ahora se dan cuenta de que el segmento de TEXTO de cualquier dylib o imagen se puede asignar a múltiples procesos, se leerá de manera perezosa y todas esas páginas se pueden compartir entre esos procesos. Ahora podemos juntar todas estas características, y te dije Mach-o, ahora te das cuenta de que el segmento de texto de cualquier dylib o imagen se puede asignar a múltiples procesos, se leerá con pereza y todas esas páginas se pueden compartir entre esos procesos.
¿Qué pasa con el segmento de DATOS? El segmento de DATOS es de lectura y escritura, por lo que para eso tenemos un truco llamado copiar en escritura, es algo similar a la clonación que se ve en el sistema de archivos de Apple. ¿Qué pasa con el segmento de datos? El segmento de datos se lee y escribe, por lo que tenemos lo que se llama una técnica de copia en escritura, que es algo similar a la clonación como se ve en el sistema de archivos de Apple.Lo que hace copiar y escribir es compartir de manera optimista la página de DATOS entre todos los procesos. Lo que hacen copiar y escribir es compartir de manera optimista páginas de datos entre todos los procesos.
¿Qué sucede cuando un proceso, siempre que solo lea las variables globales, el intercambio funciona? ¿Qué sucede cuando un proceso comparte trabajo siempre que solo lea variables globales?
Pero tan pronto como un proceso intenta escribir en su página de DATOS, se produce la copia y la escritura. Pero tan pronto como un proceso intenta escribir en sus páginas de datos, se produce una copia y escritura.
La copia y escritura hace que el kernel haga una copia de esa página en otra RAM física y redirija el mapeo para ir a esa. Copiar y escribir hacen que el kernel copie la página en otra RAM física y redirija la asignación a esa RAM física.
De modo que un proceso ahora tiene su propia copia de esa página. Entonces un proceso ahora tiene su propia copia de la página.
Lo que nos lleva a páginas limpias versus páginas sucias. Esto nos lleva a la página limpia y sucia.
Entonces esa copia se considera una página sucia. Entonces esa copia se considera una página sucia.
Una página sucia es algo que contiene información específica del proceso. Las páginas sucias son páginas que contienen información específica del proceso.
Una página limpia es algo que el kernel podría regenerar más tarde si fuera necesario, como por ejemplo al volver a leer desde el disco. Una página limpia es aquella que el kernel puede regenerar si es necesario más adelante, como por ejemplo al volver a leerla desde el disco.
Por tanto, las páginas sucias son mucho más caras que las limpias. Por tanto, las páginas sucias son mucho más caras que las limpias.
Y lo último es que los límites de los permisos están en los límites de las páginas. El último punto es que los límites de los permisos están en los límites de la página.
Con esto me refiero a que los permisos permiten marcar una página como legible, escribible o ejecutable, o cualquier combinación de ellos. Lo que quiero decir con permisos es que puedes marcar una página como legible, escribible, ejecutable o cualquier combinación de estos.
Entonces, juntemos todo esto, hablé sobre el formato Mach-O, algo sobre la memoria virtual, veamos cómo funcionan juntos. Juntemos esto, hablé sobre el formato Mach-O, un poco sobre la memoria virtual, y veamos cómo funcionan juntos.
Ahora voy a avanzar y hablar un poco sobre cómo funciona el dyld y en unos momentos los guiaré a través de esto, pero por ahora, solo quiero mostrarles cómo se relaciona esto entre Mach-O y la memoria virtual. Ahora voy a saltarme un poco y hablaré un poco sobre cómo funciona dyld, y lo explicaré en detalle en un momento, pero por ahora, solo quiero mostrarles cómo se relaciona esto entre Mach-O y la memoria virtual.
Entonces tenemos un archivo dylib aquí y, en lugar de leerlo en la memoria, lo asignamos en la memoria. Tenemos un archivo dylib aquí y, en lugar de leerlo en la memoria, lo asignamos en la memoria.
Entonces, en memoria, este dylib habría tomado ocho páginas. En la memoria, este dylib ocupa 8 páginas.
Los ahorros, la razón por la que es diferente son estos ZeroFills. Lo que lo hace diferente son estos rellenos cero.
Entonces resulta que la mayoría de las variables globales son cero inicialmente. Entonces la mayoría de las variables globales comienzan como 0.
Entonces, la estática [inaudible] realiza una optimización que mueve todas las variables globales cero hasta el final y luego no ocupa espacio en el disco. Entonces, la [inaudible] estática se optimizó para mover todas las 0 variables globales hasta el final y luego no ocupar espacio en el disco.
Y en su lugar, usamos la función VM para decirle a la VM que la primera vez que se accede a esta página, la llena con ceros. En su lugar, utilizamos una función de VM para indicarle que la llene con ceros la primera vez que accede a esta página.
Por lo que no requiere lectura. Por lo que no requiere lectura.
Entonces, lo primero que tiene que hacer dyld es mirar el encabezado de Mach, en la memoria, en este proceso. Entonces, lo primero que hace dyld es mirar el encabezado Mach en la memoria durante este proceso.
Entonces mirará el cuadro superior en la memoria, cuando eso suceda, no hay nada allí, no hay asignación a una página física, por lo que ocurre una falla de página. Verá el cuadro superior en la memoria y cuando esto suceda, no habrá nada allí, no habrá ninguna asignación a la página física, por lo que se producirá el error de página.
En ese momento, el kernel se da cuenta de que esto está asignado a un archivo, por lo que leerá la primera página del archivo, la colocará en la RAM física y establecerá la asignación. En este punto, el núcleo se da cuenta de que el mapa es para un archivo, por lo que lee la primera página del archivo, la coloca en la RAM física y le configura el mapa.
Ahora dyld puede empezar a leer el encabezado de Mach. Ahora, dyld puede empezar a leer el encabezado de Mach.
Lee el encabezado de Mach, el encabezado de Mach dice Oh, hay información en el segmento LINKEDIT que debes consultar. Leerá el encabezado de Mach y el encabezado de Mach dirá que hay información en el fragmento de LINKEDIT que necesita ver.
De nuevo, dyld deja caer lo que hay en el cuadro inferior en el proceso uno. Una vez más, dyld deja el contenido del cuadro inferior del proceso 1.
Lo que nuevamente provoca un error de página. Esto volverá a provocar un error de página.
El kernel lo repara leyendo en otra página física de la RAM, LINKEDIT. El kernel lo repara leyendo en otra página física LINKEDIT de RAM.
Ahora dyld puede esperar un LINKEDIT. Ahora, dyld puede esperar LINKEDIT.
Ahora en proceso, LINKEDIT le dirá a dyld que necesita hacer algunas correcciones en esta página de DATOS para que este dylib sea ejecutable. Ahora, durante este proceso, LINKEDIT le dirá a dyld que necesita hacer algunas correcciones en esta página de datos para que dylib sea ejecutable.
Entonces, sucede lo mismo, dyld ahora lee algunos datos de la página DATOS, pero hay algo diferente aquí. Sucede lo mismo, dyld ahora lee algunos datos de la página de datos, pero aquí hay algo diferente.
dyld en realidad va a escribir algo, en realidad va a cambiar esa página de DATOS y en este punto, se produce una copia al escribir. dyld escribirá algo, cambiará esa página de datos y, en ese momento, se producirá la copia en escritura.
Y esta página se ensucia. Esta página se está ensuciando.Entonces, ¿qué habrían sido 8 páginas de RAM sucia si simplemente hubiera mallocado ocho páginas y luego leyera el contenido? Tendría ocho páginas de RAM sucia. Entonces, ¿cuál es la memoria sucia de 8 páginas? Si pierdo 8 páginas y luego sigo leyendo, tendré 8 páginas de memoria sucia.
Pero ahora sólo tengo una página de RAM sucia y dos páginas limpias. Pero ahora solo tengo una página de memoria sucia y dos páginas de memoria limpia.
Entonces, ¿qué pasará cuando el segundo proceso cargue el mismo dylib? Entonces, ¿qué sucede cuando el segundo proceso carga el mismo dylib?
Entonces, en el segundo proceso, dyld sigue los mismos pasos. En la segunda pasada, dyld sigue los mismos pasos.
Primero mira el encabezado de Mach, pero esta vez el kernel dice, ah, ya tengo esa página en algún lugar de la RAM, por lo que simplemente redirige el mapeo para reutilizar esa página sin que se haya realizado iO. Primero mira el encabezado de Mach, pero esta vez el kernel dice, ah, ya tengo esa página en algún lugar de la RAM, así que simplemente redirige el mapa para reutilizar esa página, no iOs.
Lo mismo piensas con LINKEDIT, es mucho más rápido. Al igual que LINKEDIT, es más rápido.
Ahora llegamos a la página de DATOS, en este punto el núcleo tiene que mirar para ver si la página de DATOS, la copia limpia, todavía existe en algún lugar de la RAM, y si es así, puede reutilizarla, si no, tiene que volver a leerla. Ahora miremos la página de datos, en este punto el kernel tiene que mirar la página de datos y ver si todavía existe una copia limpia en algún lugar de la RAM, si es así, puede reutilizarla, si no, tiene que volver a leerla.
Y ahora, en este proceso, dyld ensuciará la RAM. En el proceso, dyld contamina la RAM.
Ahora el último paso es que LINKEDIT solo es necesario mientras dyld realiza sus operaciones. El último paso es LINKEDIT, que solo se requiere cuando dyld realiza la operación.
Por lo tanto, puede indicarle al kernel, una vez que esté hecho, que ya no necesita estas páginas LINKEDIT, puede reclamarlas cuando alguien más necesite RAM. Puede indicarle al kernel que una vez hecho esto, ya no necesita esas páginas LINKEDIT y puede reclamarlas cuando alguien más necesite la RAM.
Entonces, el resultado es que ahora tenemos dos procesos que comparten estos dylibs, cada uno habría tenido ocho páginas, o un total de 16 páginas sucias, pero ahora solo tenemos dos páginas sucias y una página limpia compartida. El resultado es que ahora tenemos dos procesos que comparten estos dylibs, cada uno con 8 páginas, o 16 páginas sucias en total, pero ahora solo tenemos dos páginas sucias y una página compartida limpia.
Otras dos cosas menores que quiero repasar son cómo afecta la seguridad a dyld, estos dos grandes aspectos de seguridad que han impactado a dyld. Las otras dos pequeñas cosas de las que quiero hablar son cómo la seguridad afecta a dyld, y estas dos grandes cosas afectan a dyld.
Uno es ASLR, aleatorización del diseño del espacio de direcciones, esta es una tecnología de una o dos décadas de antigüedad, donde básicamente se aleatoriza la dirección de carga. Uno es ASLR, aleatorización del diseño del espacio de direcciones, que es una tecnología de hace diez o veinte años en la que básicamente se cargan direcciones de forma aleatoria.
El segundo es la firma de código, tiene que ser así, muchos de ustedes han tenido que lidiar con la firma de código, en Xcode, y piensan en la firma de código como si ejecutan un hash criptográfico sobre todo el archivo y luego lo firman con su firma. El segundo es la firma de código. Mucha gente se ha ocupado de la firma de código en Xcode. La firma de código consiste simplemente en ejecutar un hash criptográfico en todo el archivo y luego firmarlo con una firma.
Bueno, para validar ese tiempo de ejecución, eso significa que se tendría que volver a leer todo el archivo. Para verificar el tiempo de ejecución, esto significa que se debe volver a leer todo el archivo.
Entonces, lo que realmente sucede en el momento de la compilación es que cada página de su archivo Mach-O obtiene su propio hash criptográfico individual. Entonces, lo que realmente sucede en el momento de la compilación es que cada página del archivo Mach-O tiene su propio hash criptográfico.
Y todos esos hashes se almacenan en LINKEDIT. Todas estas tablas hash se almacenan en LINKEDIT.
Esto permite validar que cada página no ha sido manipulada y que era de su propiedad en el momento de la página. Esto verifica cada página para garantizar que no haya sido manipulada y que sea la que poseía cuando estaba en la página.
Bien, terminamos el curso intensivo, ahora lo guiaré de ejecutivo a principal. Bien, hemos completado el curso intensivo, ahora te llevaré de ejecutivo a principal.
Entonces, ¿qué es ejecutivo? Exec es una llamada al sistema. Entonces, ¿qué es ejecutivo? Exec es una llamada al sistema.
Cuando entras en el kernel, básicamente dices: quiero reemplazar este proceso con este nuevo programa. Cuando te quedas atascado en el kernel, básicamente puedes decir: quiero reemplazar este proceso con este nuevo programa.
El kernel borra todo el espacio de direcciones y asigna el ejecutable que usted especificó. El kernel borra y asigna todo el espacio de direcciones en el ejecutable especificado.
Ahora, para ASLR, lo asigna a una dirección aleatoria. Para ASLR, se asigna a una dirección aleatoria.
Lo siguiente que hace es desde ese azar, volver a cero, marcar toda esa región como inaccesible, y con esto quiero decir que está marcada como no legible, no grabable, no ejecutable. Lo siguiente que hace es desde ese azar, de regreso a 0, marcar toda el área como inaccesible, quiero decir, la marca como ilegible, no grabable, no ejecutable.
El tamaño de esa región es de al menos 4 KB para procesos de 32 bits y de al menos 4 GB para procesos de 64 bits. El tamaño de esta área debe ser de al menos 4 KB para procesos de 32 bits y 4 GB para procesos de 64 bits.
Esto detecta cualquier referencia de puntero NULL y también prevé más bits, detecta cualquier truncamiento de puntero. Capta cualquier referencia de puntero nulo y, al predecir más bits, detecta cualquier truncamiento de puntero.
Ahora, la vida fue fácil durante las primeras dos décadas de Unix porque todo lo que hago es mapear un programa, configurar la PC en él y comenzar a ejecutarlo. Durante las primeras décadas, la vida en Unix era simple porque todo lo que hacía era mapear un programa, colocar mi PC en él y comenzar a ejecutarlo.
Y luego se inventaron las bibliotecas compartidas. Luego se inventaron las bibliotecas compartidas.Entonces, ¿quién carga dylibs? Rápidamente se dan cuenta de que se volvieron muy complicados rápidamente y que la gente del kernel no quería que el kernel lo hiciera, por lo que crearon un programa auxiliar. Entonces, ¿quién instaló los dylibs? Rápidamente se dieron cuenta de que se estaban volviendo muy complejos muy rápidamente y que la gente del kernel no quería que el kernel lo hiciera, por lo que se creó un programa auxiliar.
En nuestra plataforma se llama dyld. Nuestra plataforma se llama dyld.
En otros Unix es posible que lo conozcas como LD. En otros Unix es posible que lo conozcas como LD.
entonces. Entonces.
Entonces, cuando el núcleo termina de mapear un proceso, ahora mapea otro Mach-O llamado dyld en ese proceso en otra dirección aleatoria. Entonces, cuando el kernel ha terminado de mapear el proceso, ahora mapea otro Mach-O llamado dyld al proceso en otra dirección aleatoria.
Configura la PC en dyld y terminemos de iniciar el proceso. Configure la PC en dyld y deje que dyld termine de iniciar el proceso.
Ahora dyld se está ejecutando en proceso y su trabajo es cargar todos los dylibs de los que depende y tener todo preparado y funcionando. Ahora que dyld se está ejecutando, su trabajo es cargar todos los dylibs de los que depende y tener todo listo y funcionando.
Así que sigamos esos pasos. Veamos los pasos.
Este es un montón de pasos y tiene una especie de línea de tiempo en la parte inferior aquí, a medida que avanzamos por estos, recorreremos la línea de tiempo. Es una serie de pasos y tiene una línea de tiempo en la parte inferior y, a medida que avanzamos, avanzamos por la línea de tiempo.
Entonces, lo primero es que dyld tiene que mapear todos los dylibs dependientes. Primero, dyld necesita mapear todos los dylibs dependientes.
Bueno, ¿cuáles son los dylibs dependientes? Para encontrarlos, primero lee el encabezado del ejecutable principal que el kernel ya asignó. En ese encabezado hay una lista de todas las bibliotecas dependientes. ¿Qué son los dylibs dependientes? Para encontrar estos archivos, primero lee el encabezado ejecutable principal que el kernel ha asignado al encabezado de ese archivo, que es una lista de todas las bibliotecas dependientes.
Entonces hay que analizar eso. Es necesario analizarlo.
Luego tiene que encontrar cada dylib. Luego tiene que encontrar cada dylib.
Y una vez que encuentra cada dylib, tiene que abrir y ejecutar el inicio de cada archivo, debe asegurarse de que sea un archivo Mach-O, validarlo, encontrar la firma del código y registrar esa firma del código en el kernel. Una vez que encuentra cada dylib, tiene que abrir y ejecutar el comienzo de cada archivo, debe asegurarse de que sea un archivo Mach-O, verificarlo, encontrar la firma del código y registrar la firma del código con el kernel.
Y luego puede llamar a mmap en cada segmento de ese dylib. Luego puede llamar a mmap en cada segmento del dylib.
Bien, eso es bastante simple. Muy sencillo.
Su aplicación conoce el kernel dyld, dyld luego dice oh, esta aplicación depende de A y B dylib, cargue los dos y terminamos. Su aplicación conoce el kernel dyld, y luego dyld dice, esta aplicación depende de los dylibs A y B, cargue esos dos y listo.
Bueno, se vuelve más complicado, porque A. Se vuelve más complicado porque A.
dylib y B. dylib y B.
Los propios dylib podrían depender de los dylibs. Los propios dylibs pueden depender de dylibs.
Entonces, dyld tiene que hacer lo mismo nuevamente para cada uno de esos dylibs, y cada uno de los dylibs puede depender de algo que ya está cargado o de algo nuevo, por lo que tiene que determinar si ya está cargado o no, y si no, necesita cargarlo. Entonces, dyld tiene que hacer lo mismo para cada dylib, cada dylib puede depender de algo ya cargado o recién cargado, por lo que tiene que determinar si ya está cargado y, si no, necesita cargarlo.
Entonces, esto continúa y sigue. Esto continúa.
Y al final lo tiene todo cargado. Al final cargó todo.
Ahora bien, si observa un proceso, el proceso promedio en nuestro sistema carga entre 1 y 400 dylibs, por lo que son muchos dylibs para cargar. Ahora, si nos fijamos en un proceso, el proceso promedio en nuestro sistema tiene entre 1 y 400 dylibs cargados, por lo que son muchos dylibs para cargar.
Afortunadamente, la mayoría de ellos son dylibs del sistema operativo, y trabajamos mucho al construir el sistema operativo para precalcular y almacenar en caché gran parte del trabajo que dyld tiene que hacer para cargar estas cosas. Afortunadamente, la mayoría de ellos son dylibs del sistema operativo y trabajamos mucho al construir el sistema operativo para precalcular y almacenar en caché gran parte del trabajo que requiere el dyld para cargar estas cosas.
Entonces, los dylibs del sistema operativo se cargan muy, muy rápido. Entonces, los dylibs del sistema operativo se cargan muy, muy rápido.
Ahora hemos cargado todos los dylibs, pero todos están flotando independientemente unos de otros, y ahora tenemos que unirlos. Ahora que tenemos todos los dylibs cargados, pero todos en sus propios flotadores, debemos unirlos.
Eso se llama arreglos. Esto es lo que se llama se puede arreglar.
Pero una cosa sobre las correcciones es que hemos aprendido que debido a la firma del código no podemos alterar las instrucciones. Pero una cosa que hemos aprendido sobre la corrección es que en realidad no podemos cambiar las instrucciones debido a la firma del código.
Entonces, ¿cómo llama un dylib a otro dylib si no se pueden cambiar las instrucciones de cómo llama? Bueno, volvemos a llamar a nuestro viejo amigo y le agregamos muchas indirectas. Entonces, ¿cómo llama un dylib a otro dylib si no se pueden cambiar las instrucciones de cómo se llama? Bueno, llamemos a un viejo amigo y hablemos mucho de manera indirecta.
Entonces, nuestra generación de código se llama PIC dinámico. Entonces nuestra generación de código se llama PIC dinámico.
Está ubicado en un código independiente, lo que significa que el código se puede cargar en la dirección y es dinámico, lo que significa que las cosas se abordan indirectamente. Es un código independiente de la ubicación, lo que significa que el código se puede cargar en direcciones, y es dinámico, lo que significa que las cosas se abordan indirectamente.Lo que eso significa es llamar de una cosa a otra, la cogeneración en realidad crea un puntero en el segmento de DATOS y ese puntero apunta a lo que desea llamar. Esto significa que para llamar de una cosa a otra, co-gen en realidad crea un puntero en el segmento de datos que apunta a la cosa a llamar.
El código carga ese puntero y salta al puntero. El código carga ese puntero y salta a él.
Entonces, todo lo que hace dyld es corregir punteros y datos. Entonces, lo que hace dyld es corregir los punteros y los datos.
Ahora bien, hay dos categorías principales de reparaciones: rebase y encuadernación, entonces, ¿cuál es la diferencia? Entonces, rebasar es si tiene un puntero que apunta dentro de su imagen y cualquier ajuste necesario para eso, el segundo es vinculante. Ahora bien, hay dos tipos principales de correcciones, rebase y vinculación, entonces, ¿cuál es la diferencia? Entonces, si tiene un puntero a su imagen y necesita algún ajuste, el segundo es vinculante.
La vinculación es si estás apuntando a algo fuera de tu imagen. La vinculación es cuando señalas algo fuera de tu imagen.
Y cada uno necesita arreglarse de manera diferente, así que seguiré los pasos. Cada uno requiere una solución diferente, por lo que cubriré los pasos uno por uno.
Pero primero, si tienes curiosidad, hay un comando, dyld info, con un montón de opciones. Pero primero, si tienes curiosidad, hay un comando, dyld info, con muchas opciones.
Puede ejecutar esto en cualquier binario y verá todas las correcciones que dyld tendrá que hacer para que ese binario lo prepare. Puede ejecutar esto en cualquier binario y verá todas las modificaciones realizadas por dyld en ese binario.
Así que rebase. Así que revalorización.
Bueno, en la antigüedad se podía especificar una dirección de carga preferida para cada dylib, y esa dirección de carga preferida era el enlazador estático y dyld trabajaban juntos de modo que, si lo cargaba en esa dirección de carga preferida, todos los punteros y datos que se suponía codificaban internamente eran correctos y dyld no tendría que hacer ninguna corrección. En la antigüedad, puede especificar la dirección de carga prioritaria para cada dylib, y la dirección de carga prioritaria es el vinculador estático y dyld trabajan juntos; si carga, la dirección de carga prioritaria, todos los punteros y datos deben estar en el código interno, ser correcto y dyld no tiene que hacer nada para organizarlo.
Pero hoy en día, con ASLR, su dylib se carga en una dirección aleatoria. Pero ahora, con ASLR, su dylib se carga en una dirección aleatoria.
Se deslizó a otra dirección, lo que significa que todos esos punteros y datos ahora todavía apuntan a la dirección anterior. Se deslizó a otra dirección, lo que significa que todos esos punteros y datos ahora todavía apuntan a la dirección anterior.
Entonces, para arreglarlos, necesitamos calcular la diapositiva, que es cuánto se ha movido, y para cada uno de esos punteros interiores, básicamente agregarles el valor de la diapositiva. Para resolver estos problemas, necesitamos calcular el control deslizante, es decir, cuánto se ha movido, y para cada puntero interno, debemos agregarles el valor del control deslizante.
Entonces, rebasar significa revisar todos los punteros de datos, que son internos, y básicamente agregarles una diapositiva. Entonces, reubicar significa iterar a través de todos los punteros de datos, que son internos, y básicamente agregarles una diapositiva.
Entonces el concepto es muy simple: leer, agregar, escribir, leer, agregar, escribir. El concepto es simple, leer, sumar, escribir, leer, sumar, escribir.
Pero ¿dónde están esos indicadores de datos? Donde se encuentran esos punteros en su segmento, están codificados en el segmento LINKEDIT. Pero ¿dónde están esos indicadores de datos? Estos punteros están en su segmento, codificados en el segmento LINKEDIT.
Ahora, en este punto, todo lo que hemos tenido es todo mapeado, por lo que cuando comenzamos a hacer el cambio de base, en realidad estamos causando fallas de página en todas las páginas de DATOS. Ahora, en este punto, lo que tenemos es todo lo asignado, por lo que cuando comenzamos a hacer el cambio de base, en realidad estamos causando fallas de página en todas las páginas de datos.
Y luego provocamos copias y escrituras a medida que las cambiamos. Cuando los cambiamos, se producen copias y escrituras.
Por lo tanto, el cambio de base a veces puede resultar costoso debido a toda la iO. Por lo tanto, la reubicación a veces puede resultar costosa debido a iOs.
Pero un truco que hacemos es hacerlo secuencialmente y, desde el punto de vista del núcleo, ve que las fallas de datos ocurren secuencialmente. Pero un truco que vamos a hacer es hacerlo secuencialmente, de modo que desde la perspectiva del kernel, verá que los errores de datos ocurren secuencialmente.
Y cuando ve eso, el núcleo lee por adelantado, lo que hace que el iO sea menos costoso. Cuando ve esto, el kernel lee los datos con anticipación, lo que reduce el costo de iOs.
Entonces, lo siguiente es el enlace, el enlace es para punteros que apuntan fuera de su dylib. El siguiente es el enlace, que es un puntero hacia fuera del dylib.
En realidad, están vinculados por nombre, en realidad son la cadena, en este caso, malloc almacenado en la edición del enlace, que dice que este puntero de datos debe apuntar a malloc. En realidad, están vinculados por nombre, en realidad son cadenas y, en este ejemplo, malloc se almacena en la edición del enlace, que dice que este puntero de datos debe apuntar a malloc.
Entonces, en tiempo de ejecución, dyld realmente necesita encontrar la implementación de ese símbolo, lo que requiere muchos cálculos, revisando las tablas de símbolos. Entonces, en tiempo de ejecución, dyld realmente necesita encontrar la implementación de ese símbolo, lo cual es computacionalmente intensivo y requiere mirar la tabla de símbolos.
Una vez que se encuentra, los valores se almacenan en ese puntero de datos. Una vez que se encuentra, ese valor se almacena en ese puntero de datos.
Entonces esto es mucho más complejo computacionalmente que el rebase. Entonces es mucho más complicado que el retargeting.
Pero hay muy poca iO porque el rebase ya ha hecho la mayor parte de la iO. Pero hay muy pocos iO porque Chongji ya ha completado la mayoría de los iO.
A continuación, ObjC tiene un montón de estructuras de DATOS, una estructura de datos de clase que es un puntero a sus métodos y un puntero a un súper brillo, etc. A continuación, ObjC tiene un montón de estructuras de datos, las estructuras de datos de clase son punteros a sus métodos y punteros a superbrillante, etc.Casi todos se arreglan, mediante rebase o encuadernación. Casi todos estos se solucionan mediante rebase o encuadernación.
Pero hay algunas cosas adicionales que requiere el tiempo de ejecución de ObjC. Pero el tiempo de ejecución de ObjC requiere algo más.
El primero es que ObjC es un lenguaje dinámico y puede solicitar que una clase se fundamente por su nombre. La primera es que ObjC es un lenguaje dinámico y puedes solicitar que una clase sea confirmada por su nombre.
Eso significa que el tiempo de ejecución de ObjC debe mantener una tabla de todos los nombres de las clases a las que se asignan. Esto significa que el tiempo de ejecución de ObjC debe mantener una tabla que contenga todos los nombres de las clases a las que están asignados.
Entonces, cada vez que carga algo, define una clase, su nombre debe registrarse en una tabla global. Entonces, cada vez que se carga algo, se define una clase y su nombre debe registrarse en una tabla global.
A continuación, en C++ es posible que haya oído hablar del problema del frágil ivar, lo siento. A continuación, en C++ es posible que hayas oído hablar del problema del frágil ivar, lo siento.
Problema de clase base frágil. Problema de clase base frágil.
No tenemos ese problema con ObjC porque una de las correcciones que hacemos es cambiar las compensaciones de todos los ivars dinámicamente, en el momento de la carga. ObjC no tiene este problema porque una solución que hicimos fue cambiar dinámicamente las compensaciones de todos los ivars en carga.
A continuación, en ObjC puedes definir categorías que cambian los métodos de otra clase. A continuación, en ObjC, puedes definir categorías que alteren métodos de otra clase.
A veces, esos están en clases que no están en su imagen en otro dylib, por lo que esas correcciones de métodos deben aplicarse en este punto. A veces estas clases no están en la imagen de otro dylib y estos métodos deben aplicarse en ese momento.
Y, por último, ObjC [inaudible] se basa en que los selectores sean únicos, por lo que necesitamos selectores únicos. Finalmente, ObjC [inaudible] se basa en que los selectores sean únicos, por lo que necesitamos selectores únicos.
Ahora que hemos hecho el trabajo de arreglar todos los DATOS, ahora podemos hacer todos los arreglos de DATOS que se pueden describir básicamente de forma estática. Ahora que hemos realizado todas las correcciones de datos, ahora podemos hacer todas las correcciones de datos que básicamente se pueden describir estáticamente.
Así que ahora es nuestra oportunidad de realizar correcciones dinámicas de DATOS. Ahora es el momento de que hagamos la reparación dinámica de datos.
Entonces, en C++, puedes tener un inicializador, puedes decir [inaudible] es igual a cualquier expresión que desees. En C++, puedes tener un inicializador y puedes decir [inaudible] es igual a cualquier expresión que desees.
Esa expresión arbitraria, en este momento, debe ejecutarse y se ejecuta en este momento. Esta expresión arbitraria, que ahora debe ejecutarse, se ha ejecutado.
Entonces, el compilador de C++ genera iniciadores para estas inicializaciones de DATOS arbitrarias. El compilador de C++ genera inicializadores para estas inicializaciones de datos arbitrarios.
En ObjC, hay algo llamado método +load. En ObjC, hay un método llamado +carga.
Ahora el método +load está en desuso, le recomendamos que no lo utilice. El método +load ahora está en desuso y le recomendamos que no lo utilice.
Le recomendamos que utilice una inicialización más. Le recomendamos que utilice +inicialización.
Pero si tiene uno, se ejecuta en este punto. Pero si tienes uno, se ejecuta en este punto.
Entonces, ahora tengo este gran gráfico, tenemos la parte superior ejecutable principal, de la que dependen todos los dylibs, este enorme gráfico, tenemos que ejecutar inicializadores. Ahora que tengo este gran gráfico, tenemos el ejecutable principal encima del que dependen todos los dylibs, este gran gráfico, tenemos que ejecutar el inicializador.
¿En qué orden los queremos? Bueno, los analizamos de abajo hacia arriba. ¿En qué orden queremos que se ordenen? Contemos de abajo hacia arriba.
Y la razón es que, cuando se ejecuta una inicialización, es posible que sea necesario llamar a algún dylib y desea asegurarse de que los dylibs ya estén listos para ser llamados. La razón es que cuando se ejecuta un init, es posible que deba llamar a algunos dylibs, y debe asegurarse de que los dylibs estén listos para ser llamados.
Entonces, al ejecutar los inicializadores desde la parte inferior hasta la clase de aplicación, es seguro llamar a algo de lo que depende. Por lo tanto, al ejecutar el inicializador de abajo hacia arriba, puede llamar con seguridad a las cosas de las que depende.
Entonces, una vez que todos los iniciadores hayan terminado, finalmente podremos llamar al programa dyld principal. Una vez que se completen todas las rutinas de inicialización, ahora finalmente podemos llamar al programa principal de dyld.
Entonces sobrevivieron a esta parte teórica, ahora todos son expertos en cómo comienzan los procesos, ahora saben que dyld es un programa auxiliar, carga todas las bibliotecas dependientes, arregla todas las páginas de DATOS, ejecuta inicializadores y luego salta a principal. Ya superó esta parte teórica, ahora son expertos en cómo se inician los procesos y saben que dyld es un programa auxiliar que carga todas las bibliotecas dependientes, corrige todas las páginas de datos, ejecuta el inicializador y luego salta a principal.
Ahora, para poner en práctica toda esta teoría que has aprendido, me gustaría entregársela a Louis, quien te dará algunos consejos prácticos. Ahora, para poner en práctica la teoría que has aprendido, me gustaría dejársela a Louis, quien te dará algunos consejos prácticos.
Gracias, Nick. Gracias, Nick.
Todos hemos tenido esa experiencia en la que sacamos el teléfono del bolsillo, presionamos el botón de inicio y luego tocamos la aplicación que queremos ejecutar. A todos nos ha pasado: sacamos el teléfono del bolsillo, pulsamos el botón de inicio y hacemos clic en la aplicación que queremos ejecutar.
Y luego toque, toque y toque nuevamente algún botón porque no responde. Luego haga clic, haga clic y vuelva a hacer clic en algún botón porque no responde.
Cuando eso me sucede, es realmente frustrante y quiero eliminar la aplicación. Cuando esto me pasa me siento muy frustrado y quiero eliminar la aplicación.
Soy Louis Gerbarg, trabajo en dyld y hoy vamos a discutir cómo hacer que su aplicación se inicie instantáneamente, para que sus usuarios estén encantados. Soy Louis Gerbarg, trabajo en dyld y hoy vamos a hablar sobre cómo hacer que su aplicación se inicie instantáneamente para que sus usuarios estén contentos.Primero que nada, analicemos lo que vamos a abordar en esta parte de la charla. Primero, analicemos esta parte.
Vamos a discutir qué tan rápido realmente necesitas iniciar para que tus usuarios tengan una buena experiencia. Analizaremos qué tan rápido realmente necesitas para brindarles a tus usuarios una buena experiencia.
Cómo medir ese tiempo de lanzamiento. Cómo medir el tiempo de lanzamiento.
Porque puede ser muy difícil. Porque es muy difícil.
Las formas estándar de medir su aplicación no se aplican antes de que se pueda ejecutar su código. Hasta que el código pueda ejecutarse, los métodos estándar para medir una aplicación no se aplican.
Vamos a repasar una lista de las razones comunes por las que su código, o lo siento, vamos a repasar una lista de las razones comunes por las que su lanzamiento puede ser lento. Enumeraremos algunas razones comunes para explicar por qué su código se inicia lentamente. Lo sentimos, enumeraremos algunas razones comunes para explicar por qué su código se inicia lentamente.
Y finalmente, veremos una manera de solucionar todas las desaceleraciones. Finalmente de lo que queremos hablar es de la solución a todos los problemas de lentitud.
Así que les voy a dar un pequeño spoiler del resto de mi charla. Así que en el resto de mi discurso les contaré un pequeño episodio.
Necesitas hacer menos cosas [risas]. Necesitas hacer menos [risas].
Ahora bien, no me refiero a que su aplicación deba tener menos funciones, lo que digo es que su aplicación tiene que hacer menos cosas antes de ejecutarse. Ahora bien, no estoy diciendo que su aplicación deba tener menos funciones, estoy diciendo que su aplicación tiene que hacer menos cosas antes de poder ejecutarse.
Queremos que descubra cómo posponer algunos de sus comportamientos de lanzamiento para inicializarlos justo antes de la ejecución. Esperamos que pueda descubrir cómo retrasar algunos comportamientos de inicio para que se inicialicen antes de la ejecución.
Entonces, analicemos los objetivos, qué tan rápido queremos lanzar. Entonces, hablemos de objetivos, de qué tan rápido queremos lanzarlos.
Bueno, el tiempo de lanzamiento para varias plataformas es diferente. El tiempo de inicio es diferente para diferentes plataformas.
Pero una buena regla general es que 400 milisegundos es un buen tiempo de lanzamiento. Sin embargo, una buena regla general es que 400 milisegundos es un buen tiempo de inicio.
Ahora, la razón de esto es que tenemos animaciones de inicio en el teléfono para dar una sensación de continuidad entre la pantalla de inicio y su aplicación, cuando ve que se ejecuta. La razón de esto es que iniciamos la animación en el teléfono para darles una sensación de continuidad cuando ves la pantalla de inicio y tus aplicaciones ejecutándose.
Y esas animaciones toman tiempo, y esas animaciones le dan la oportunidad de ocultar sus tiempos de lanzamiento. Estas animaciones toman tiempo y le brindan la oportunidad de ocultar su hora de inicio.
Obviamente, eso puede ser diferente, en diferentes contextos las extensiones de su aplicación también son aplicaciones que deben iniciarse, se inician en diferentes períodos de tiempo. Obviamente, esto puede ser diferente, en diferentes circunstancias las extensiones de su aplicación también son las aplicaciones que deben iniciarse, y se inician en diferentes momentos.
Y un teléfono, un televisor y un reloj son cosas diferentes, pero 400 milisegundos es un buen objetivo. Los teléfonos móviles, los televisores y los relojes son cosas diferentes, pero 400 milisegundos es un buen objetivo.
Nunca puedes tardar más de 20 segundos en iniciarse. El tiempo de lanzamiento no puede exceder los 20 segundos.
Si tarda más de 20 segundos, el sistema operativo cerrará su aplicación, suponiendo que esté pasando por un bucle infinito, y todos hemos tenido esa experiencia. Si tarda más de 20 segundos, el sistema cerrará su aplicación, suponiendo que esté pasando por un bucle infinito, a todos nos ha pasado.
Cuando haces clic en una aplicación, aparece una pantalla de inicio, no responde y luego simplemente desaparece, y eso es normalmente lo que sucede aquí. Cuando tocas una aplicación, aparece en la pantalla de inicio, deja de responder y luego desaparece, que suele ser lo que sucede aquí.
Finalmente, es muy importante realizar la prueba en el dispositivo compatible más lento. Finalmente, es importante realizar la prueba en el dispositivo compatible más lento.
Entonces, esos temporizadores son valores constantes en todos los dispositivos compatibles con nuestras plataformas. Por lo tanto, estos temporizadores son constantes para todos los dispositivos compatibles en nuestra plataforma.
Entonces, si alcanzas los 400 milisegundos en un iPhone 6S que estás usando para realizar pruebas en este momento, probablemente apenas lo alcances, probablemente no lo alcanzarás en un iPhone 5. Entonces, si tocas durante 400 milisegundos en el iPhone 6S que estás probando, es posible que solo lo toques y es posible que no lo toques en el iPhone 5.
Así que hagamos un resumen de la parte de la charla de Nick. Repasemos el discurso de Nick.
¿Qué tenemos que hacer para iniciar? Tenemos que analizar imágenes, mapear imágenes, cambiar la base de las imágenes, vincular imágenes, ejecutar inicializadores de imágenes y luego llamar a main. Lo que debemos hacer para comenzar es analizar la imagen, mapear la imagen, restablecer la imagen, vincular la imagen, ejecutar la inicialización de la imagen y luego llamar a main.
Si eso parece mucho, lo es. Estoy exhausto con sólo decirlo. Si eso parece mucho, lo es, y estoy exhausto con solo decirlo.
Y luego de eso, tenemos que llamar a UIApplicationMain, verás que en tus aplicaciones ObjC o en tus aplicaciones Swift se maneja implícitamente. Luego, debemos llamar a UIApplicationMain, que verá manejado implícitamente en su aplicación ObjC o Swift.
Eso hace algunas otras cosas, incluida la ejecución de los inicializadores del marco y la carga de las puntas. También puede hacer algunas otras cosas, incluida la ejecución de inicializadores de marco y cargar puntas.
Y finalmente recibirá una llamada del delegado de su aplicación. Finalmente, recibirás una devolución de llamada en el delegado de la aplicación.
Menciono estos dos últimos porque se cuentan en esos tiempos de 400 milisegundos que acabo de mencionar. Menciono los dos últimos porque se calculan utilizando los 400 milisegundos que acabo de mencionar.
Pero no vamos a discutirlos en esta charla. Pero no los discutiremos en esta charla.Si desea tener una mejor visión de lo que sucede allí, hay una charla de 2012 sobre la capacidad de respuesta del rendimiento de la aplicación iOS. Si desea comprender mejor lo que sucede allí, hay una charla de 2012, Capacidad de respuesta del rendimiento de las aplicaciones iOS.
Le recomiendo que regrese y vea el video. Te recomiendo que regreses y veas el video.
Pero eso es lo último de lo que vamos a hablar ahora. Pero ese es el último del que vamos a hablar ahora.
Entonces, sigamos adelante, una cosa más de la que quiero hablar: lanzamientos cálidos versus lanzamientos fríos. Entonces, pasemos a la otra cosa que quiero decir: emisión caliente y emisión fría.
Entonces, cuando inicias una aplicación, hablamos de lanzamientos en frío y en caliente. Cuando inicia una aplicación, analizamos el inicio en caliente y el inicio en frío.
Y un inicio en caliente es una aplicación donde la aplicación ya está en la memoria, ya sea porque se inició y se cerró anteriormente, y todavía está en el disco de caché del kernel, o porque simplemente la copió. Mientras que un arranque en caliente es cuando la aplicación ya está en la memoria porque se inició y salió antes, todavía está en el disco del kernel o porque acaba de copiarla.
Un lanzamiento en frío es un lanzamiento donde no está en el discoche. Un arranque en frío es un arranque que no está en el disco.
Y, por lo general, es más importante medir un lanzamiento en frío. La emisión de frío suele ser la medida más importante.
La razón por la que es más importante medir un inicio en frío es cuando el usuario inicia una aplicación después de reiniciar el teléfono, o por primera vez en mucho tiempo, es cuando realmente desea que sea instantáneo. La razón más importante para un arranque en frío es que cuando el usuario inicia la aplicación después de reiniciar el teléfono, o por primera vez en mucho tiempo, realmente desea que sea instantáneo.
Para medirlos, realmente necesita reiniciar entre mediciones. Para poder medirlos, es necesario reiniciar entre mediciones.
Dicho esto, si estás trabajando para mejorar tus lanzamientos en caliente, tus lanzamientos en frío también tenderán a mejorar. Dicho esto, si estás mejorando los arranques en caliente, los arranques en frío también mejorarán.
Puede realizar ciclos de desarrollo rápidos en lanzamientos en caliente, pero luego, de vez en cuando, realizar pruebas con un lanzamiento en frío. Puede ejecutar ciclos de desarrollo rápidos en arranques en caliente, pero ocasionalmente utilice arranques en frío para realizar pruebas.
Entonces, ¿cómo medimos el tiempo antes del main? Bueno, tenemos un sistema de medición integrado en dyld, puedes acceder a él configurando una variable de entorno. Entonces, ¿cómo medimos el tiempo antes del main? Tenemos un sistema de medición incorporado en dyld, al que puede acceder configurando una variable de entorno.
Estadísticas de impresión DYLD. DYLD imprime datos.
Y en realidad ha estado disponible en los sistemas operativos de envío, pero imprime mucha información de depuración interna que no es particularmente útil, le falta información que probablemente desee. En realidad, ya está disponible en los sistemas operativos lanzados, pero imprime mucha información de depuración interna que no es particularmente útil y pierde parte de la información que quizás desee.
Y lo estamos arreglando hoy. Estamos abordando este tema hoy.
Por lo tanto, ha mejorado significativamente en los nuevos sistemas operativos. Por lo tanto, ha mejorado significativamente en el nuevo sistema operativo.
Publicará mucha más información relevante para usted que debería brindarle formas prácticas de mejorar sus tiempos de lanzamiento. Le proporcionará información más relevante que le brindará formas prácticas de mejorar su tiempo de publicación.
Y estará disponible en la semilla 2. Estará disponible en la semilla 2.
Entonces, otra cosa de la que quiero hablar con esto es que el depurador tiene que pausar el inicio en cada carga de dylib para analizar los símbolos de su aplicación y cargar sus puntos de interrupción, a través de un cable USB que puede llevar mucho tiempo. Entonces, otra cosa que diría es que el depurador tiene que pausar el inicio cada vez que se carga dylib para resolver los símbolos en la aplicación y cargar puntos de interrupción a través del cable USB, lo que puede llevar mucho tiempo.
Pero dyld lo sabe y resta el tiempo de espera del depurador de los números que registra. Pero dyld lo sabe y resta el tiempo de depuración del número registrado.
Así que no tienes que preocuparte por eso, pero lo notas porque dyld te dará números mucho más pequeños de los que observarás al mirar el reloj de la pared. Así que no tienes que preocuparte por eso, pero lo notarás porque dyld te dará un número mucho menor que el que verías si miraras el reloj de la pared.
Eso es lo que se espera y se entiende, y todo va correctamente si lo ven, pero sólo quería tomar nota de ello. Esto es esperado y comprensible, y si lo ve, es todo normal, pero solo quería escribirlo.
Entonces, sigamos adelante, para configurar una variable de entorno en Xcode, simplemente vaya al editor de esquemas y la agregue así. Sigamos adelante y establezcamos una variable de entorno en Xcode, simplemente vaya al editor de esquemas y agréguela así.
Una vez que haga eso, obtendrá el nuevo registro de la consola en la salida, la salida de la consola se registrará. Una vez que haga esto, obtendrá el nuevo registro de la consola para generar, registro de salida de la consola.
¿Y cómo se ve eso? Bueno, así es como se ve el resultado y tenemos una barra de tiempo en la parte inferior que representa las diferentes partes del mismo. ¿Cómo se ve eso? Así es como se ve el resultado, con una barra de tiempo en la parte inferior para representar las diferentes partes del mismo.
Y agreguemos una cosa más. Agreguemos una cosa más.
Agreguemos un indicador para ese objetivo de 400 milisegundos, que esta aplicación en la que estoy trabajando no alcanza. Agreguemos un indicador para el objetivo de 400 milisegundos, que no se alcanza con esta aplicación que estoy usando.
Entonces, si miran, estos son básicamente los pasos que Nick analizó para iniciar una aplicación, así que repasémoslos en orden. Si nos fijamos en esto, estos son básicamente los pasos que Nick analizó sobre el inicio de una aplicación. Veámoslos en orden.Entonces, la carga dylib, lo más importante que hay que entender acerca de la carga dylib y la desaceleración que verá, es que las dylibs integradas pueden ser costosas. Entonces, la carga dylib, una cuestión importante para comprender la carga dylib y la desaceleración que verá, es que las dylibs integradas pueden ser costosas.
Entonces Nick dijo que una aplicación promedio puede tener entre 100 y 400 dylibs. Nick dijo que una aplicación puede tener entre 100 y 400 dylibs en promedio.
Pero los dylibs del sistema operativo son rápidos porque cuando construimos el sistema operativo, tenemos formas de calcular previamente muchos de esos datos. Pero los dylibs del sistema operativo son rápidos porque cuando construimos un sistema operativo, tenemos formas de precalcular grandes cantidades de datos.
Pero no tenemos todos los dylib en todas las aplicaciones cuando creamos el sistema operativo. Pero al crear un sistema operativo, no todas las aplicaciones tienen dylibs.
No podemos precalcularlos para los dylibs que incorporas con tu aplicación, por lo que tenemos que pasar por un proceso mucho más lento a medida que los cargamos. No podemos precalcularlos para dylibs integrados en la aplicación, por lo que al cargarlos tenemos que pasar por un proceso mucho más lento.
Y la solución para esto es que solo necesitamos usar menos dylibs y eso puede resultar complicado. La solución a este problema es que solo necesitamos usar menos dylibs, lo que puede resultar tosco.
Y no estoy diciendo que no puedas usar ninguno, pero aquí hay un par de opciones con las que puedes fusionar dylibs existentes. No digo que no puedas usar ninguna, pero aquí hay dos opciones que puedes usar para fusionar dylibs existentes.
Puedes usar archivos estáticos y vincularlos a ambos, a aplicaciones de esa manera. Puede utilizar archivos estáticos y vincularlos a ambas aplicaciones.
Y tiene una opción de carga diferida, que consiste en usar dlopen, pero dlopen causa algunos problemas sutiles de rendimiento y corrección, y en realidad resulta en hacer más trabajo más adelante, pero se difiere. Puede elegir la carga diferida, incluso usando dlopen, pero dlopen causa algunos problemas sutiles de rendimiento y corrección; en realidad hace que se haga más trabajo más adelante, pero se retrasa.
Por lo tanto, es una opción viable, pero debes pensarlo detenidamente y, si es posible, lo desaconsejaría. Entonces, es una opción viable, pero deberías pensarlo y te disuadiría si es posible.
Entonces, tengo una aplicación aquí que actualmente tiene 26 dylibs, y se necesitan 240 milisegundos solo para cargarlos, pero si la cambio y fusiono esos dylibs en dos dylibs, entonces solo toma 20 milisegundos para cargar los dylibs. Tengo una aplicación que actualmente tiene 26 dylibs y se necesitan 240 ms para cargarlas, pero si la cambio y fusiono estos dylibs en dos dylibs, solo se necesitan 20 ms para cargar estos dylibs.
Entonces todavía puedo tener dylibs, todavía puedo usarlos para compartir funcionalidades entre mi aplicación y mi extensión, pero limitarlos será muy útil. Entonces todavía puedo usar dylibs, todavía puedo usarlos para compartir funcionalidad entre mi aplicación y mis extensiones; sin embargo, limitarlos sería muy útil.
Y entiendo que esta es una compensación que está haciendo entre la conveniencia del desarrollo y el tiempo de lanzamiento de la aplicación para sus usuarios. Entiendo que se trata de un equilibrio entre la comodidad del desarrollo para los usuarios y el tiempo de inicio de la aplicación.
Porque cuantos más dylibs tenga, más fácil será crear y volver a vincular su aplicación y más rápidos serán sus ciclos de desarrollo. Porque cuantos más dylibs haya, más fácil será crear y volver a vincular la aplicación y más rápido será el ciclo de desarrollo.
Así que absolutamente puedes y debes usar algunos, pero es bueno tratar de apuntar a un número limitado, yo diría que un buen objetivo es aproximadamente media docena. Así que absolutamente puedes y debes usar algunos, pero es mejor apuntar a un número limitado y yo diría que un buen objetivo es alrededor de seis.
Entonces, ahora que hemos arreglado nuestro conteo de dylib, pasemos al siguiente lugar donde estamos teniendo una desaceleración. Ahora que hemos resuelto el problema del recuento de dylib, pasemos a la siguiente desaceleración.
Entre 350 milisegundos en vinculación y rebase. 350 milisegundos entre vinculación y reubicación.
Entonces, como mencionó Nick, el rebase tiende a ser más lento debido a iO y la vinculación tiende a ser computacionalmente costosa, pero ya está hecho en iO. Como mencionó Nick, el rebase será más lento debido a iO y el costo computacional de la vinculación será mayor, pero se realiza con iO.
Así que iO es para ambos y están combinados, el momento también está combinado. Entonces iO fue para ambos, llegaron y llegó el momento.
Entonces, si entramos y miramos eso, todo eso es arreglar los punteros en la sección DATOS. Si entramos y lo miramos, todos estos son punteros a la sección de datos fijos.
Entonces, lo que tenemos que hacer es corregir menos punteros. Entonces lo que tenemos que hacer es corregir menos indicaciones.
Nick le mostró una herramienta que puede ejecutar para ver qué punteros se están arreglando en la sección DATOS, información de dyld. Nick le muestra una herramienta que puede ejecutar para ver qué punteros se están arreglando en DATOS, sección, información de dyld.
Y muestra en qué segmentos y secciones se encuentran las cosas, por lo que les dará una buena idea de lo que se está arreglando. Muestra partes y piezas de cosas, lo que le da una buena idea de lo que se está restaurando.
Por ejemplo, si ve un símbolo de una clase ObjC en la sección ObjC, probablemente tenga varias clases ObjC. Por ejemplo, si ve símbolos para clases de ObjC en la sección ObjC, probablemente tenga varias clases de ObjC.
Entonces, una de las cosas que puede hacer es simplemente reducir la cantidad de objetos de clases ObjC e ivars que tiene. Una cosa que puede hacer es reducir la cantidad de objetos de clase ObjC e ivars que tiene.
Por lo tanto, hay una serie de estilos de codificación que fomentan clases muy pequeñas, que tal vez solo tengan una o dos funciones. Por lo tanto, existen muchos estilos de codificación que fomentan clases muy pequeñas, que pueden tener solo una o dos funciones.Y esos patrones particulares pueden resultar en una desaceleración gradual de sus aplicaciones a medida que agrega más y más. Y, a medida que agrega más y más aplicaciones, estos patrones específicos pueden hacer que sus aplicaciones se ralenticen gradualmente.
Entonces debes tener cuidado con eso. Entonces debes tener cuidado con estos.
Ahora tener 100 o 1000 clases no es un problema, pero hemos visto aplicaciones con 5, 10, 15, 20.000 clases. Ahora tener 100 o 1000 clases no es un problema, pero hemos visto aplicaciones con 5, 10, 15, 20 mil clases.
Y en esos casos, eso puede agregar hasta 7 u 800 milisegundos al tiempo de inicio para que el kernel los localice. En estos casos, el tiempo de arranque para que el kernel los localice aumentará en 7 u 800 milisegundos.
Otra cosa que puedes hacer es intentar reducir el uso de funciones virtuales de C++. Otra cosa que puedes hacer es minimizar el uso de funciones virtuales de C++.
Entonces, las funciones virtuales crean lo que llamamos tablas V, que son iguales a los metadatos ObjC en el sentido de que crean estructuras en la sección DATOS que deben arreglarse. Entonces, las funciones virtuales crean lo que llamamos tablas V, que son lo mismo que los metadatos de ObjC porque crean estructuras en la parte de datos que deben corregirse.
Son más pequeños que ObjC, son más pequeños que los metadatos de ObjC, pero siguen siendo importantes para algunas aplicaciones. Son más pequeños que ObjC y más pequeños que los metadatos de ObjC, pero siguen siendo importantes para algunas aplicaciones.
Puedes usar estructuras Swift. Se pueden utilizar estructuras rápidas.
Por lo tanto, Swift tiende a utilizar menos datos que indiquen correcciones de este tipo. Por lo tanto, Swift tiende a utilizar menos datos que tengan sugerencias para tales correcciones.
Y Swift es más adaptable y puede cogenerarse mejor para evitar mucho de eso, por lo que migrar a Swift es una excelente manera de mejorar esto. Además, Swift es más fácil de integrar y funciona mejor en conjunto para evitar esto, por lo que pasar a Swift es una excelente manera de mejorar.
Y otra cosa, se debe tener cuidado con los códigos generados por máquinas, por lo que tenemos casos en los que se pueden describir algunas estructuras en términos de DSL o algún lenguaje personalizado y luego tener un programa que genera otro código a partir de ello. Otra cosa es que se debe tener cuidado con el código generado por máquina, por lo que tenemos ejemplos en los que se describe alguna estructura en un DSL o lenguaje personalizado y luego se hace que un programa genere otro código a partir de ella.
Y si esos programas generados tienen muchos punteros, pueden resultar muy costosos porque cuando generas tu código puedes generar estructuras muy, muy grandes. Si estos programas generados tienen muchos punteros, pueden resultar muy costosos porque cuando generas código puedes generar estructuras muy, muy grandes.
Hemos visto casos en los que esto genera megabytes y megabytes de datos. Hemos visto que esto puede resultar en megabytes de datos.
Pero la ventaja es que normalmente tienes mucho control porque puedes simplemente cambiar el generador de código para usar algo que no sean punteros, por ejemplo estructuras basadas en desplazamiento. Pero el beneficio es que normalmente tienes mucho control, ya que puedes cambiar el generador de código para usar algo que no sea un puntero, como una estructura basada en desplazamiento.
Y esa será una gran victoria. Esta será una gran victoria.
Entonces, en este caso, veamos lo que está pasando aquí conmigo, con mi tiempo de carga. En este caso, veamos lo que está pasando aquí, el tiempo de carga.
Y tengo al menos 10.000 clases, en realidad tengo 20.000, tantas que se salieron de la diapositiva. Tengo al menos 10.000 cursos, de hecho tengo 20.000 cursos, muchos de ellos simplemente salieron de las diapositivas.
Y si lo reduzco a 1000 clases, simplemente reduzco mis tiempos de lanzamiento, mi tiempo en esta parte del lanzamiento de 350 a 20 milisegundos. Si lo reduzco a 1000 clases reduzco mi tiempo de inicio, paso de 350ms a 20ms para esta parte.
Entonces, ahora, todo menos el inicializador está en realidad por debajo de esa marca de 400 milisegundos, por lo que lo estamos haciendo bastante bien. Ahora, excepto el inicializador, todo lo demás está por debajo de 400 ms y lo estamos haciendo muy bien.
Entonces, para la configuración de ObjC, Nick mencionó todo lo que tenía que hacer. Para la creación de ObjC, Nick mencionó todo lo que tenía que hacer.
Tenía que hacer el registro de clase, tiene que lidiar con los ivars no frágiles, tiene que hacer el registro de categoría y tiene que hacer el selector uniqing. Tiene que realizar el registro de clases, tiene que manejar ivars no friables, tiene que realizar el registro de clases y tiene que realizar la unicidad del selector.
Y no voy a dedicar mucho tiempo a esto en absoluto, y la razón por la que no lo haré es que resolvimos todo eso arreglando el cambio de base y los datos, y vinculando antes. No voy a dedicar demasiado tiempo a esto, y la razón por la que no voy a dedicar demasiado tiempo a esto es que resolvimos todos estos problemas restableciendo la base y los datos, así como los enlaces anteriores.
Todas las reducciones serán las mismas que usted desea hacer aquí. Todas las reducciones aquí son iguales.
Así que aquí obtenemos una pequeña ganancia gratis, es pequeña. Así que aquí tenemos una pequeña ganancia gratis, es pequeña.
Son 8 milisegundos. Esto es 8 milisegundos.
Pero no hicimos nada explícito al respecto. Pero no hicimos nada explícito.
Y ahora, finalmente, vamos a ver mis inicializadores, que son los 10 segundos más importantes aquí. Finalmente, llegamos a mis inicializadores y son los 10 segundos más importantes aquí.
Así que voy a profundizar un poco más en esto que Nick. Así que voy a profundizar un poco más que Nick.
Hay dos tipos de inicializadores, inicializadores explícitos, cosas como +cargar. Hay dos tipos de inicializadores, inicializadores explícitos como +load.
Como dijo Nick, recomendamos reemplazar eso con +initialize, lo que hará que el tiempo de ejecución de ObjC inicialice su código cuando se fundamentaron las clases en lugar de cuando se cargue el archivo. Como dijo Nick, recomendamos reemplazarlo con +initialize, lo que hará que el tiempo de ejecución de ObjC inicialice el código cuando se confirme la clase, en lugar de cuando se cargue el archivo.O, en C/C++ hay un atributo que se puede colocar en funciones que harán que las genere como inicializadores, por lo que es un inicializador explícito, que preferimos que no uses. Alternativamente, en C/C++, hay un atributo que puede poner en una función que generará esos inicializadores, que es un inicializador explícito y solo esperamos que no lo use.
Preferimos que los reemplace con inicializadores de sitios de llamadas. Preferiríamos que los reemplace con inicializadores de sitios de llamadas.
Entonces, cuando hablo de inicializadores de sitio de llamada me refiero a cosas como enviar una vez. Al llamar al inicializador del sitio, me refiero a algo así como enviarlo una vez.
O si está en código multiplataforma, pthread una vez. Alternativamente, si está utilizando código multiplataforma, utilice pthread una vez.
O si estás en código C++, estándar una vez. O si estás en código C++, estándar una vez.
Todas estas funciones tienen básicamente el mismo tipo de funcionalidad en la que cualquier código en uno de estos bloques se ejecutará la primera vez que se acceda y solo eso. Todas estas funciones tienen básicamente la misma funcionalidad, cualquier código dentro de un bloque se ejecutará en el primer acceso y eso es todo.
El envío una vez está muy, muy optimizado en nuestro sistema. La programación una vez está muy, muy optimizada en nuestro sistema.
Después de la primera ejecución, es básicamente equivalente a que no se ejecute ninguna operación, por lo que recomiendo encarecidamente que, en lugar de usar, inicializadores explícitos. Después de la primera ejecución, es básicamente equivalente a que no se ejecute ninguna operación encima, por lo que recomiendo encarecidamente no utilizar inicializadores explícitos.
Entonces pasemos a los inicializadores implícitos. Sigamos hablando de inicializadores implícitos.
Entonces, los inicializadores implícitos son lo que Nick describió principalmente de los globales de C++ con inicializadores no triviales, con constructores no triviales. Por lo tanto, Nick describe los inicializadores de aplicaciones en variables globales de C++, que incluyen inicializadores y constructores no triviales.
Y una opción es reemplazarlos con inicializadores de sitios de llamadas como acabamos de mencionar. Una opción es que puedes reemplazarlos con los inicializadores del sitio de llamadas que acabamos de mencionar.
Ciertamente, hay lugares donde puede colocar elementos globales con estructuras no globales o punteros a objetos que inicializará. Por supuesto, puede colocar variables globales con estructuras no globales en algún lugar o punteros a objetos para inicializar.
Otra opción es que no tengas inicializadores no triviales. Otra opción es que no tengas un inicializador no trivial.
Entonces, en C++ hay inicializadores llamados POD, datos antiguos y simples. En c++ hay un inicializador llamado POD, datos antiguos y simples.
Y si sus objetos son simplemente datos antiguos, el enlazador estático o estático precalculará todos los datos para la sección DATOS, los presentará como solo los datos que se ven allí, no es necesario ejecutarlos, no es necesario arreglarlos. Si sus objetos son simplemente datos antiguos, estáticos o estáticos, el vinculador precalculará todos los datos en la sección de datos, como los datos que ve aquí, no es necesario ejecutarlos y no es necesario corregirlos.
Finalmente, puede ser muy difícil encontrarlos porque están implícitos, pero tenemos una advertencia en el compilador -Wglobal-constructors y si lo hace, le dará advertencias cada vez que genere uno de estos. Finalmente, es difícil encontrarlos porque están implícitos, pero tenemos una advertencia en el compilador-wglobal-constructor que le avisará si genera uno de estos.
Entonces es bueno agregar eso a las banderas que usa tu compilador. Por eso es mejor agregarlo a los indicadores utilizados por el compilador.
Otra opción es simplemente reescribirlos en Swift. Otra opción es reescribirlos rápidamente.
Y la razón es que Swift tiene variables globales y se inicializarán, se garantiza que se inicializarán antes de usarlas. La razón es que Swift tiene variables globales que se inicializan y se garantiza que se inicializarán antes de usarlas.
Pero la forma en que lo hace es, en lugar de usar un inicializador, detrás de escena, usa el envío una vez para usted. Pero la forma en que se implementa es que, detrás de escena, en lugar de usar un inicializador, usa un despacho por usted.
Utiliza uno de esos inicializadores de sitios de llamadas. Utiliza uno de los inicializadores del sitio de llamada.
Entonces, cambiar a Swift se encargará de esto por usted, por lo que recomiendo encarecidamente que sea una opción. Entonces, pasar a Swift lo ayudará a resolver este problema, por lo que le recomiendo encarecidamente que lo haga como una opción.
Finalmente, en sus inicializadores, no llame a dlopen, eso afectará mucho el rendimiento por varias razones. Finalmente, en su inicializador, no llame a dlopen, esto afectará considerablemente el rendimiento por muchas razones.
Cuando dyld se ejecuta es antes de que se inicie la aplicación y podemos hacer cosas como desactivar el bloqueo, porque somos de un solo subproceso. Cuando dyld se está ejecutando, aún no ha comenzado, podemos desactivar el bloqueo porque somos de un solo subproceso.
Tan pronto como ocurrieron los dlopens, en esas situaciones, el gráfico de cómo nuestros inicializadores deben ejecutarse cambia, podríamos tener múltiples subprocesos, tenemos que activar el bloqueo, simplemente será un gran desastre de rendimiento. Una vez que ocurre el dlopen, en estos casos, ¿cómo ejecuta el inicializador el gráfico modificado? Es posible que tengamos varios subprocesos y tengamos que abrir el bloqueo, lo que será un gran desastre de rendimiento.
También puede tener estancamientos sutiles y comportamientos indefinidos. También puede tener puntos muertos sutiles y comportamiento indefinido.
Además, no inicie subprocesos en sus inicializadores, básicamente por el mismo motivo. Además, no inicie subprocesos en inicializadores, básicamente por la misma razón.
Puede configurar un texto silenciado si es necesario y el texto silenciado incluso si lo desea, los textos silenciados preferidos incluso tienen valores estáticos predefinidos con los que puede configurarlos y que no ejecutan código. Puede establecer un texto silencioso si es necesario, texto silencioso, e incluso hay texto silencioso preferido, valores estáticos predefinidos que puede configurar sin ejecutar código.Pero, en realidad, iniciar un hilo en su inicializador es potencialmente un gran problema de rendimiento y corrección. Pero, en realidad, iniciar un hilo en un inicializador es un posible problema de rendimiento y corrección.
Aquí tenemos algo de código, tengo una clase C++ con un inicializador no trivial. Aquí tenemos algo de código, tengo una clase de C++ que tiene un inicializador importante.
Estoy teniendo problemas con la conexión. Hay un problema con mi conexión.
Inténtelo de nuevo en un momento. Inténtelo de nuevo más tarde.
Bueno, gracias Siri. Gracias Siri.
Tengo un inicializador no trivial. Tengo un inicializador no trivial.
Y supongo que lo tenía listo para depurar, todo comentado y bueno, estoy en 50 milisegundos en total. Creo que lo depuré todo comentado y son solo 50 ms en total.
Tengo mucho tiempo para inicializar mis puntas y hacer todo lo demás, estamos en muy buena forma. Tuve tiempo suficiente para inicializar la punta y hacer otras cosas y estábamos en bastante buena forma.
Ahora que hemos analizado eso, hablemos de lo que deberíamos saber si esto fuera realmente largo y bastante denso. Ahora que hemos cubierto eso, hablemos de lo que debemos saber si este es realmente largo y denso.
La primera es utilizar estadísticas de impresión dyld para medir tus tiempos y agregarlas a tus conjuntos de rendimiento o agresión. La primera es usar dyld para imprimir estadísticas para medir tus tiempos, agregar esto a tu conjunto de rendimiento o ataque.
Por lo tanto, puede realizar un seguimiento del rendimiento de su aplicación a lo largo del tiempo, de modo que cuando esté haciendo algo activamente no lo encuentre meses después y tenga problemas para depurarlo. Por lo tanto, puede realizar un seguimiento del rendimiento de su aplicación a lo largo del tiempo, de modo que mientras trabaja activamente en algo, lo pierde de vista meses después y es difícil depurarlo.
Puede mejorar el tiempo de inicio de su aplicación reduciendo la cantidad de dylibs que tiene, reduciendo la cantidad de clases ObjC que tiene y eliminando sus inicializadores estáticos. Puede mejorar el tiempo de inicio de su aplicación reduciendo la cantidad de dylibs, reduciendo la cantidad de clases ObjC y eliminando los inicializadores estáticos.
Y puedes mejorar en general usando más Swift porque simplemente hace lo correcto. A menudo, puedes mejorar usando velocidades más rápidas porque es lo correcto.
Finalmente, se desaconseja el uso de dlopen, ya que causa problemas sutiles de rendimiento que son difíciles de diagnosticar. Finalmente, se desaconseja el uso de dlopen ya que puede causar problemas sutiles de rendimiento que son difíciles de diagnosticar.
Para obtener más información, puede ver la URL en la pantalla. Consulte la URL en la pantalla para obtener más información.
Hay varias sesiones relacionadas más adelante en la semana y nuevamente, está la sesión de rendimiento de la aplicación de 2012 que aborda las otras partes del lanzamiento de la aplicación, que le recomendamos encarecidamente que vea, si está interesado. Habrá un par de sesiones relacionadas a finales de esta semana; la sesión Rendimiento de aplicaciones de 2012 cubrirá otras partes de la publicación de aplicaciones y es muy recomendable si está interesado.
Gracias por venir a todos, que tengáis una gran semana. Gracias a todos por venir y que tengáis una gran semana.
What to read next
Want more posts about iOS?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #iOS?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home