用分析器查看这个告诉我,大部分时间实际上都花在了链接器上。
您的分析方法非常出了点问题。
首先,“链接器”在应用程序运行时不会运行,只有 loader(又名 rtld,又名 ld-linux)会运行。我假设您的意思不是加载器,而不是链接器。
其次,加载器确实有一些运行时成本在启动时,但是由于您调用的每个函数都只解析一次,因此加载器运行时成本的比例在运行任何可感知时间(超过大约 1 分钟)的应用程序应该很快接近零。
所以本质上动态链接实际上太慢了(有时)。
您可以通过使用-Wl,-z,now 链接器标志链接,让加载程序在加载时解析共享库中的所有动态符号。
如果我将这个共享库静态链接到 musl,然后让(动态链接的)glibc 应用程序 dlopen 它,那会安全吗?
这不仅不安全,而且很可能根本不起作用(除了大多数琐碎的共享库)。
是否存在多个 libc 的一般问题?
将多个 libc 链接到一个进程中会导致太多问题。
更新:
在加载时解析所有符号与我想要的完全相反,因为进程在加载共享对象期间被终止,之后它运行正常。
听起来你正在使用dlopen而进程已经执行时间关键的实时任务。
这不是明智之举:dlopen(除其他外)调用malloc,从磁盘读取数据,执行mmap 调用等等。所有需要锁,并且可以等待任意长的时间。
通常的解决方案是让应用程序在进入时间关键循环之前执行初始化(加载您的库将是其中的一部分)。
由于您无法控制应用程序,您唯一能做的就是告诉应用程序开发人员他们当前的需求(如果这些实际上是他们的需求)无法满足 - 他们必须提供一些方法来执行初始化在进入时间关键部分之前,否则他们将总是冒SIGKILL的风险。加快您的库加载速度只会使SIGKILL 出现频率较低,但不会完全删除它。
更新 2:
是的,我知道我能做的最好的事情就是降低频率而不是“解决”问题,只是尝试减轻它。
您应该查看prelink。它可以显着降低执行重定位所需的时间。这并不能保证您选择的预链接地址将可用,因此您有时可能仍会收到SIGKILLed,但这可能是一种有效的缓解措施。