Linux共享库两种加载方式简述

     动态库技术一般能减小程序的大小,节省空间,提升效率,具备很高的灵活性,对于升级软件版本也更加容易。与静态库不一样,动态库里面的函数不是执行程序自己 的一部分,而是在程序执行时按需载入,其执行代码能够同时在多个程序中共享。因为在编译过程当中没法知道动态库函数的地址,因此须要在运行期间查找,这对程 序的性能会有影响。 程序员

 

共享库 

     对于共享库来说,它只包括2个段:只读的代码段 和可修改的数据段。堆和栈段,只有进程才有。若是你在共享库的函数里,分配了一块内存,这段内存将被算在调用该函数的进程的堆中。代码段因为其内容是对每 个进程都是同样的,因此它在系统中是惟一的,系统只为其分配一块内存,多个进程之间共享。数据段因为其内容对每一个进程是不同的,因此在连接到进程空间 后,系统会为每一个进程建立相应的数据段。也就是说若是一个共享库被N个进程连接,当这N个进程同时运行时,同时共享一个代码段,每一个进程拥有一个数据段,系统中共有N个数据段。PICposition independent code,使.so文件的代码段变为真正意义上的共享。若是编译时不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象须要重定位重定位会修改代码段的内容,这就形成每一个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy。 函数

 

加载方式

     1. 静态加载 性能

 

     在程序编译的时候加上-l”选项,指定其所依赖的动态库,这个库的名字将记录在ELF文件的.dynamic节。在程序运行时,loader会预先将程序所依赖的全部动态库都加载在进程空间中。 编码

     优势:动态库的接口调用简单,能够直接调用。 spa

     缺点:动态库的生存周期等于进程的生存周期,其加载时机不灵活。 code

 

     2. 动态加载 orm

     在程序中编码来指定加载动态库的时机,常常使用的函数dlopen和dlclosehtm

     优势:动态库加载的时机很是灵活,能够很是细致的定义动态库的生存周期。 对象

     缺点动态库的接口调用起来比较麻烦,同时还要关注动态库的生存周期。 接口

=====================================================

      #include <dlfcn.h>

  void * dlopen( const char * pathname, int mode );

  函数描述:

  在dlopen的()函数以指定模式打开指定的动态链接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。

  mode:分为这两种

  RTLD_LAZY 暂缓决定,等有须要时再解出符号

  RTLD_NOW 当即决定,返回前解除全部未决定的符号。

  RTLD_LOCAL  不容许导出符号

  RTLD_GLOBAL 容许导出符号

  RTLD_NODELETE

      RTLD_NOLOAD

      RTLD_DEEPBIND          //具体含义可经过man查看dlopen函数说明

  返回值:

  打开错误返回NULL

  成功,返回库引用

  编译时候要加入 -ldl (指定dl库)

 

  int dlclose (void *handle);

 

  函数描述:

   dlclose用于关闭指定句柄的动态连接库,只有当此动态连接库的使用计数为0时,才会真正被系统卸载。

 

 

     在dlopen一个共享库时,

a、进程会加载该共享库的代码段和数据段,同时为这个共享库计数加1

b、进程查找该共享库的dynamic节,查看其所依赖的共享库。

c、首先检查所依赖库是否已经被加载,若是已被加载,则为这个共享库计数加1。若是未被加载,则加载其代码段和数据段,而后为这个共享库计数加1

d、再查找这些库所依赖的库。最终进程会为每一个加载的共享库维护一个依赖的计数。

 

     在dlclose共享库时:

a、首先将该共享库的计数减1,若是该共享库依赖计数为0,则卸载该共享库。

b、在dynamic节中,查找其所依赖的共享库。

c、为每一个共享库的计数减1,若是该共享库依赖计数为0,则卸载该共享库。

d、重复上面的步骤。

  • 优势:

a、能够在程序启动的时候,减小加载库的数量,这样能够加快进程的启动速度和减小加载库的内存使用。

b、为进程提供了卸载共享库的机会,这样就能够回收共享库代码段和数据段所占用的内存。

  • 缺点:

对于程序员编码来说,会产生必定的疑惑。一个static的对象的生存周期是贯穿在进程始终的,实际上不是这样。在动态库中的static对象,其生命周期等于该动态库的生命周期。采用静态连接的方式,动态库的生命周期等于进程的生命周期;而采用动态加载的方式,则是不一样的。

 

参考:

《嵌入式Linux内存与性能详解》

相关文章
相关标签/搜索