¿Por qué el inicio de una aplicación en Linux es más lento cuando se utilizan bibliotecas compartidas?

StackOverflow https://stackoverflow.com/questions/1410691

  •  05-07-2019
  •  | 
  •  

Pregunta

En el dispositivo integrado en el que estoy trabajando, el tiempo de inicio es un tema importante. Toda la aplicación consta de varios ejecutables que utilizan un conjunto de bibliotecas. Como el espacio en la memoria FLASH es limitado, nos gustaría usar bibliotecas compartidas.

La aplicación funciona de la manera habitual cuando se compila y se vincula con bibliotecas compartidas y la cantidad de memoria FLASH se reduce según lo esperado. La diferencia con la versión que está vinculada a las librerías estáticas es que el tiempo de inicio de la aplicación es aproximadamente 20 segundos más y no tengo idea de por qué.

La aplicación se ejecuta en una CPU ARM9 a 180 MHz con Linux 2.6.17 OS, 16 MB de FLASH (sistema de archivos JFFS) y 32 MB de RAM.

¿Fue útil?

Solución

Las bibliotecas compartidas de Bacause deben estar vinculadas en tiempo de ejecución, generalmente mediante dlopen () o algo similar. No hay tal paso para las bibliotecas estáticas.

Editar: algunos detalles más. dlopen tiene que realizar las siguientes tareas.

  • Busca la biblioteca compartida
  • cargarlo en la memoria
  • Cargar recursivamente todas las dependencias (y sus dependencias ...)
  • Resolver todos los símbolos

Esto requiere bastantes operaciones de IO para lograrlo.

En un programa vinculado estáticamente, todo lo anterior se realiza en tiempo de compilación, no en tiempo de ejecución. Por lo tanto, es mucho más rápido cargar un programa vinculado estáticamente.

En su caso, la diferencia es exagerada por el hardware relativamente lento en el que se ejecuta su código.

Otros consejos

Este es un buen ejemplo del clásico intercambio de velocidad y espacio.

Puedes vincular estáticamente todos tus ejecutables para que sean más rápidos pero luego tomarán más espacio

OR

Puede tener bibliotecas compartidas que ocupan menos espacio pero también más tiempo para cargar.

Así que decide lo que quieres sacrificar.

Hay muchos factores para esta diferencia (SO, compilador, etc.) pero se puede encontrar una buena lista de razones aquí . Básicamente, las bibliotecas compartidas se crearon por razones de espacio y gran parte de la " magia " involucrado para hacer que funcionen toma un golpe de rendimiento.

(Como nota histórica, el navegador original de Netscape en Linux / Unix era un ejecutable grande y grande estáticamente vinculado).

Esto puede ayudar a otros con problemas similares:

La razón por la que el inicio tardó tanto en mi caso fue que la configuración predeterminada del GCC es exportar todos los símbolos dentro de una biblioteca. Una gran mejora es establecer una configuración del compilador " -fvisibility = hidden " ;.

Todos los símbolos que el lib tiene que exportar tienen que ser aumentados con la declaración

__attribute__ ((visibilidad (" predeterminado ")))

vea wiki de gcc
y el excelente artículo cómo escribir bibliotecas compartidas

Bien, he aprendido ahora que el uso de bibliotecas compartidas tiene sus desventajas con respecto a la velocidad. Encontré este artículo sobre enlace dinámico y carga enlighting. El proceso de carga parece ser mucho más largo de lo que esperaba.

Interesante ... normalmente, el tiempo de carga de una biblioteca compartida no se nota desde una aplicación grande que está estáticamente vinculada. Así que solo puedo suponer que el sistema es muy lento para cargar una biblioteca desde la memoria flash, o que la biblioteca que se está cargando está siendo verificada de alguna manera (por ejemplo, las aplicaciones .NET ejecutan una suma de comprobación para todos los archivos DLL cargados, lo que reduce considerablemente el tiempo de inicio). algunos casos). Puede ser que las bibliotecas compartidas se carguen según sea necesario y se descarguen posteriormente, lo que podría indicar un problema de configuración.

Lo siento, no puedo dejar de decir por qué, pero creo que es un problema con su dispositivo / sistema operativo ARM. ¿Ha intentado instrumentar el código de inicio, o vincular estáticamente con una de las bibliotecas más utilizadas para ver si eso hace una gran diferencia? También coloque las bibliotecas compartidas en el mismo directorio que la aplicación para reducir el tiempo necesario para buscar la biblioteca en el servicio fijo.

Una opción que me parece obvia, es vincular estáticamente todos los programas en un solo binario. De esa manera, continuará compartiendo la mayor cantidad de código posible (probablemente más que antes), pero también evitará la sobrecarga del enlazador dinámico Y ahorrará el espacio de tener el enlazador dinámico en el sistema.

Es bastante fácil combinar varios ejecutables en el mismo, normalmente solo examinas argv y decides a qué rutina llamar en función de eso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top