Linux程序动态库加载优化

  作者:zhanhailiang 日期:2014-10-26

linux程序动态库加载流程简介

linux从程序(program或对象)变成进程(process或进程),简单说来需要经过三步:

  1. fork进程,在内核创建进程相关内核项,加载进程可执行文件;
  2. 查找依赖的.so,逐一加载映射虚拟地址;
  3. 初始化程序变量;

如下例通过strace查看pwd命令执行过程:

[root@~/wade/codeReview/learningc]# strace pwd
execve("/bin/pwd", ["pwd"], [/* 24 vars */]) = 0
brk(0)                                  = 0x1c77000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb011000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=29690, ...}) = 0
mmap(NULL, 29690, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06eb009000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY)      = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\356\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1921096, ...}) = 0
mmap(NULL, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f06eaa5f000
mprotect(0x7f06eabe9000, 2097152, PROT_NONE) = 0
mmap(0x7f06eade9000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18a000) = 0x7f06eade9000
mmap(0x7f06eadee000, 18696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f06eadee000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb008000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb007000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb006000
arch_prctl(ARCH_SET_FS, 0x7f06eb007700) = 0
mprotect(0x7f06eade9000, 16384, PROT_READ) = 0
mprotect(0x7f06eb012000, 4096, PROT_READ) = 0
munmap(0x7f06eb009000, 29690)           = 0
brk(0)                                  = 0x1c77000
brk(0x1c98000)                          = 0x1c98000
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=99158576, ...}) = 0
mmap(NULL, 99158576, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06e4bce000
close(3)                                = 0
getcwd("/root/wade/codeReview/learningc", 4096) = 32
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb010000
write(1, "/root/wade/codeReview/learningc\n", 32/root/wade/codeReview/learningc
) = 32
close(1)                                = 0
munmap(0x7f06eb010000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?

由此可见,如果只加载必须的动态库对程序性能有很重要的意义。

最佳实践

1. 程序test.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
main () {
    printf ("1");
    exit (0);
}

2. 编译test.c

[root@~/wade/codeReview/learningc/16]# gcc -lm -lpthread -o test test.c 

3. 通过ldd test命令查看程序运行时需要加载哪些动态库:

[root@~/wade/codeReview/learningc/16]# ldd test
	linux-vdso.so.1 =>  (0x00007fff6b5ff000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f394cefa000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f394ccdd000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f394c948000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f394d187000)

4. 通过ldd -u test命令查看程序加载了哪些不必要的动态库:

[root@~/wade/codeReview/learningc/16]# ldd -u test
Unused direct dependencies:
 
	/lib64/libm.so.6
	/lib64/libpthread.so.0

5. 通过-Wl,–as-needed编译选项只加载必须的动态库:

[root@~/wade/codeReview/learningc/16]# gcc -Wl,--as-needed -lm -o test test.c
[root@~/wade/codeReview/learningc/16]# ldd test
	linux-vdso.so.1 =>  (0x00007fffdf5ff000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f5d862cd000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5d8666a000)

参考文章:

时间: 2024-08-24 07:08:25

Linux程序动态库加载优化的相关文章

linux和windows动态库加载路径区别

# linux和windows动态库加载路径区别 ### 简介------------------------------ linux加载动态库的路径是系统目录/lib和/usr/lib.- windows加载动态库的路径是本地目录下,然后再搜索windows/system和windows/system32目录 ### 备注------------------------------ linux加载动态库的路径方式,对于习惯windows开发的开发者是不太方便的.- 其实linux下可以设置从当

linux动态库加载的秘密

摘自http://gotowqj.iteye.com/blog/1926734 摘自http://www.360doc.com/content/14/0313/13/12747488_360246417.shtml linux 下有动态库和静态库,动态库以.so为扩展名,静态库以.a为扩展名.二者都使用广泛.本文主要讲动态库方面知识. 基本上每一个linux 程序都至少会有一个动态库,查看某个程序使用了那些动态库,使用ldd命令查看 # ldd /bin/ls linux-vdso.so.1 =

linux下添加动态链接库路径、动态库加载等方法

linux下添加动态链接库路径的方法 2017年01月20日 10:08:17 阅读数:5596 Linux共享库路径配置 Linux下找不到共享库文件的典型现象为明明已经安装某个软包(如libnet,MySQL),编译连接可以正常进行,但是在运行时出现如"error while loading shared libraries: libnet.so.1:cannot open shared object file :No such file or directory"的错误提示. 原

记一起动态库加载错误问题排查过程

我们的服务器软件在一台新机器上启动的时候报错: error while loading shared libraries: libtcmalloc_mininal.so.4 No such file or directory 1,首先找找动态库libtcmalloc是否在新机器上 libtcmalloc这个动态库在目录/usr/local/lib下面,再查看/etc/ld.so.conf/gperftools.conf,它已经把目录/usr/local/lib加入到动态库搜索路径中了,为什么还会

ios 动态库加载及某个文件非ARC问题

build setting里的header search paths里增加动态库头文件的搜索路径如 /usr/include/libxml2 还要在other linker flags里增加 -lxml2 如果某个文件是非ARC,则在build phases里的compile sources里找到对应的文件增加-fno-objc-arc

动态库加载配置

cannot open shared object file: No such file or directory解决 ./move_db: error while loading shared libraries: libmysqlclient.so.15: cannot open shared object file: No such file or directory 第一步:确认有哪些Lib无法Load >ldd move_db linux-gate.so.1 => (0x0089c0

【linux】linux下动态库so文件的一些认识

来源:http://mypyg.iteye.com/blog/845915 so其实就是shared object的意思.今天看了上面的博客,感觉好吃力.赶紧做个笔记记录一下.下面的内容大多都是连接中的,穿插我自己的笔记 牵扯到ELF格式,gcc编译选项待补,简单实用的说明一下,对Linux下的so文件有个实际性的认识. 1.so文件是什么? 2.怎么生成以及使用一个so动态库文件? 3.地址空间,以及线程安全. 4.库的初始化,解析: 5.使用我们自己库里的函数替换系统函数: 1.so文件是什

共享库加载时重定位

原作者:Eli Bendersky http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries 本文的目的是解释现代操作系统怎样使得共享库加载时重定位成为可能.它关注执行在32位x86的LinuxOS.但通用的原则也适用于其它OS与CPU. 共享库有很多名字--共享库,共享对象,动态共享对象(DSO),动态链接库(DLL--假设你有Windows背景).为了统一起见.我将尽量在本文里使用"共享库

Linux下动态库(.so)和静态库(.a) 的区别

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.编译之后程序文件大,但加载快,隔离性也好.动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在.多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可. 编译动态库: -shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接.相当于一个可执行文件-fPIC:表示