深入分析linux下 动态库的显性调用(dlopen)和隐性调用区别

1. 前言

在linux环境下编程,我们如果想要使用第三方的库,基本上有以下几种方式:

  • 1、将第三方库的源码合并到我们的工程项目代码中,一起编译。
  • 2、将第三方库编译成静态库(xxx.a),我们在使用时,在Makefile中引用该静态库。
  • 3、将第三方库编译成动态库(xxx.so), 我们在使用时,隐性调用该动态库,具体表现为需要 在程序中包含动态库的 头文件,同时需要在/usr/lib路径下,存放动态库文件,以便程序调用。
  • 4、将第三方库编译成动态库(xxx.so), 我们在使用时,显性调用该动态库,在程序中,不需要包含动态库的头文件,使用 dlopen、dlsym等接口函数调用该动态库。

这4种方式:

  • 第1和2种,本质上是一样的,使用静态库,编译时,会将静态库的内容合并到工程代码中,唯一区别的是当我们拿不到第三方库的源码时,可以直接使用静态库,相当于使用一个黑盒子,静态库提供接口。
  • 第3和4种方式,我们常用的是第3种方式,也就是隐性调用,但是显性调用一种程序插件的概念,随用随加载,不用不加载。

2. 显性调用和隐性调用区别

这里我们先说结论:

  • 隐性调用:需要提前将动态库xxx.so 拷贝到 相关目录下,不管程序是否真正使用动态库,执行前会检查该动态库,如果检测不到动态库,会报错。
  • 隐性调用,程序一旦执行,会把动态库读到内存中,而不管是否会运行到动态库部分,相当于一刀切。
  • 显性调用,如果程序没有运行到dlopen,动态库文件xxx.so 是不需要拷贝到相关目录下的,程序只有在执行到dlopen时,才会检查该动态库,是一种插件形式,随用随调用。
  • 显性调用,程序开始运行后,不会立刻读取动态库到内存中,而是直行道dlopen时,才会将动态库拷贝到内存中。
名称使用方式动态库文件内存其他
隐性调用引用动态库头文件需要提前拷贝到/usr/lib/目录,否则程序无法执行程序开始执行,不管是否用到动态库功能,都会将动态库读到内存中不会额外调用插件库
显性调用不需要引用动态库头文件,但是需要引用<dlfcn.h>不一定,如果程序不会执行到动态库功能,则不需要拷贝,即便使用,也可以使用绝对路径来使用,不需要拷贝到/usr/lib/目录下只有程序执行到dlopen时,才会将动态库读入内存会额外调用linux插件库,来支持显性调用

3. 测试

测试的思路就是对比,对比源码、静态库、动态库显性调用、动态库隐性调用,这4种方式的内存占比情况。

3.1 场景

我们实现一种简单的场景,编写一个 加、减、乘、除、打印等功能的 计算库,主程序中调用该库,计算库源码如下:

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>


const char *CA_crt = \
{
    \
    "-----BEGIN CERTIFICATE-----\r\n"
    "MIIDkzCCAnugAwIBAgIJAI436FANVXhYMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV\r\n" \
    "BAYTAkNOMQ4wDAYDVQQIDAVIZWJlaTERMA8GA1UEBwwITGFuZ2ZhbmcxDDAKBgNV\r\n" \
    "BAoMA0VOTjEOMAwGA1UECwwFRU5ORVcxDzANBgNVBAMMBklvVCBDQTAgFw0yMTAz\r\n" \
    "MTEwODMyMjRaGA8yMTIxMDIxNTA4MzIyNFowXzELMAkGA1UEBhMCQ04xDjAMBgNV\r\n" \
    "BAgMBUhlYmVpMREwDwYDVQQHDAhMYW5nZmFuZzEMMAoGA1UECgwDRU5OMQ4wDAYD\r\n" \
    "VQQLDAVFTk5FVzEPMA0GA1UEAwwGSW9UIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n" \
    "AQ8AMIIBCgKCAQEAzeteOYou2GlZys4lEo+ypdXYCmpayqSdpZGIaVojLNNYqoQc\r\n" \
    "kbghLhxzJxlB72lMc3zOPrYHyG/pe9Abh198sHSU0FInjr6nTx07rUy5SsIKQNIY\r\n" \
    "sih8pxVH+7CDp9X+BNhRWGbobE0KnMO+U5XjR4+b7yGDGfaWzBxIaADYJDnbcWEs\r\n" \
    "14EfSnADE0I9A2AyqLgZTpr6sj0A8ybowl/SgJW7wT+yrymNbNlzYDZKN4ow1376\r\n" \
    "PsXiwtnN0TO2g3x9bYvIjFRpEzcyoW2/eab81ztS81YE3RslfWh74lpviOoB8z7M\r\n" \
    "Va3dQIJrsCvRjDkWueuDrw2MmC1R8tB4HtqZxQIDAQABo1AwTjAdBgNVHQ4EFgQU\r\n" \
    "h06iXX7GqtF5T19AZzkXhLSSaz4wHwYDVR0jBBgwFoAUh06iXX7GqtF5T19AZzkX\r\n" \
    "hLSSaz4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuC/J3nO01YxS\r\n" \
    "TZuhXtFio3AGkQNptFlsGjWyzxLyH2oJN7PI6KpI2XhteUzRfUN2rx7F9uwpFig8\r\n" \
    "yDphOU7fesbvRsAKkb6HhDgeMKcuPrKOM2FMj6JVcyHERJ5J7MaqcRVAS948F54n\r\n" \
    "fCAOIfvkd8Y8EmxptDnbyJ7gTwJ4mAYuXJzLtVaEZqMcAvvFdJgKHHNJhl7SqfO3\r\n" \
    "c9JJhepx0djWwR4coMc66Fe3X9lDdmhGt/t6TXxI09qGxecpj8p/VuRQ02gcLyZW\r\n" \
    "139Yg2JpWUftmyITvBCW1fNM1Uf1GGu6tsFibE+DcwhGNJ0rbBP/EzSFg1trAkUN\r\n" \
    "svRnMOVUuQ==\r\n" \
    "-----END CERTIFICATE-----"
};


int add(int a,int b)
{
    return (a + b);
}

int sub(int a, int b)
{
    return (a - b);
}

int mul(int a, int b)
{
    return (a * b);
}

int div(int a, int b)
{
    return (a / b);
}

void print_CA_info(void)
{
    printf("%s", CA_crt);
}

注: 上述代码中,包含了一个CA证书,目的是为了增加这个 动态库的体积,方便后面的比较,否则动态库太小的话,看不出区别。

测试代码逻辑:

int main(void)
{
    printf("start wait 60s...\n");
    sleep(60);
    printf("will return in 20...\n");
    print_CA_info();
    sleep(20);
    return 0;
}

上述代码中,有两部分组成,前一部分是未执行动态库内容,进行等待,后一部分则是执行动态库内的函数,这样做的目的是为了 分析 显性调用的 dlopen 前后内存区别。

3.2 源码使用

直接将动态库的源码合并到测试程序里,进行编译,运行,内存监控如下:

ubuntu@VM-0-17-ubuntu:~$ ps -ef|grep test-src
ubuntu    3826  3082  0 11:03 pts/3    00:00:00 ./test-src
ubuntu    3856  3194  0 11:03 pts/4    00:00:00 grep test-src
ubuntu@VM-0-17-ubuntu:~$ pmap -x 3826
3826:   ./test-src
Address           Kbytes     RSS   Dirty Mode  Mapping
000055662853e000       4       4       0 r-x-- test-src
000055662853e000       0       0       0 r-x-- test-src
000055662873f000       4       4       4 r---- test-src
000055662873f000       0       0       0 r---- test-src
0000556628740000       4       4       4 rw--- test-src
0000556628740000       0       0       0 rw--- test-src
000055662a2c3000     132       4       4 rw---   [ anon ]
000055662a2c3000       0       0       0 rw---   [ anon ]
00007f1b03aed000    1948    1164       0 r-x-- libc-2.27.so
00007f1b03aed000       0       0       0 r-x-- libc-2.27.so
00007f1b03cd4000    2048       0       0 ----- libc-2.27.so
00007f1b03cd4000       0       0       0 ----- libc-2.27.so
00007f1b03ed4000      16      16      16 r---- libc-2.27.so
00007f1b03ed4000       0       0       0 r---- libc-2.27.so
00007f1b03ed8000       8       8       8 rw--- libc-2.27.so
00007f1b03ed8000       0       0       0 rw--- libc-2.27.so
00007f1b03eda000      16      12      12 rw---   [ anon ]
00007f1b03eda000       0       0       0 rw---   [ anon ]
00007f1b03ede000     164     164       0 r-x-- ld-2.27.so
00007f1b03ede000       0       0       0 r-x-- ld-2.27.so
00007f1b040fb000       8       8       8 rw---   [ anon ]
00007f1b040fb000       0       0       0 rw---   [ anon ]
00007f1b04107000       4       4       4 r---- ld-2.27.so
00007f1b04107000       0       0       0 r---- ld-2.27.so
00007f1b04108000       4       4       4 rw--- ld-2.27.so
00007f1b04108000       0       0       0 rw--- ld-2.27.so
00007f1b04109000       4       4       4 rw---   [ anon ]
00007f1b04109000       0       0       0 rw---   [ anon ]
00007ffecec06000     132      12      12 rw---   [ stack ]
00007ffecec06000       0       0       0 rw---   [ stack ]
00007ffeceddd000      12       0       0 r----   [ anon ]
00007ffeceddd000       0       0       0 r----   [ anon ]
00007ffecede0000       8       4       0 r-x--   [ anon ]
00007ffecede0000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            4520    1416      80

可以看到 占用内存 约 1416kb

3.3 静态库调用

将共享库编译成静态库libcalculate.a,然后在编译测试程序时,引用该静态库,具体的编译步骤这里就省略,运行,监控内存如下:

ubuntu@VM-0-17-ubuntu:~$ ps -ef|grep test-hid-a
ubuntu    4773  3082  0 11:09 pts/3    00:00:00 ./test-hid-a
ubuntu    4794  3194  0 11:09 pts/4    00:00:00 grep test-hid-a
ubuntu@VM-0-17-ubuntu:~$ pmap -x 4773
4773:   ./test-hid-a
Address           Kbytes     RSS   Dirty Mode  Mapping
000055b2814cd000       4       4       0 r-x-- test-hid-a
000055b2814cd000       0       0       0 r-x-- test-hid-a
000055b2816ce000       4       4       4 r---- test-hid-a
000055b2816ce000       0       0       0 r---- test-hid-a
000055b2816cf000       4       4       4 rw--- test-hid-a
000055b2816cf000       0       0       0 rw--- test-hid-a
000055b282710000     132       4       4 rw---   [ anon ]
000055b282710000       0       0       0 rw---   [ anon ]
00007eff6c989000    1948    1180       0 r-x-- libc-2.27.so
00007eff6c989000       0       0       0 r-x-- libc-2.27.so
00007eff6cb70000    2048       0       0 ----- libc-2.27.so
00007eff6cb70000       0       0       0 ----- libc-2.27.so
00007eff6cd70000      16      16      16 r---- libc-2.27.so
00007eff6cd70000       0       0       0 r---- libc-2.27.so
00007eff6cd74000       8       8       8 rw--- libc-2.27.so
00007eff6cd74000       0       0       0 rw--- libc-2.27.so
00007eff6cd76000      16      12      12 rw---   [ anon ]
00007eff6cd76000       0       0       0 rw---   [ anon ]
00007eff6cd7a000     164     152       0 r-x-- ld-2.27.so
00007eff6cd7a000       0       0       0 r-x-- ld-2.27.so
00007eff6cf97000       8       8       8 rw---   [ anon ]
00007eff6cf97000       0       0       0 rw---   [ anon ]
00007eff6cfa3000       4       4       4 r---- ld-2.27.so
00007eff6cfa3000       0       0       0 r---- ld-2.27.so
00007eff6cfa4000       4       4       4 rw--- ld-2.27.so
00007eff6cfa4000       0       0       0 rw--- ld-2.27.so
00007eff6cfa5000       4       4       4 rw---   [ anon ]
00007eff6cfa5000       0       0       0 rw---   [ anon ]
00007ffdc50e7000     132       8       8 rw---   [ stack ]
00007ffdc50e7000       0       0       0 rw---   [ stack ]
00007ffdc51af000      12       0       0 r----   [ anon ]
00007ffdc51af000       0       0       0 r----   [ anon ]
00007ffdc51b2000       8       4       0 r-x--   [ anon ]
00007ffdc51b2000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            4520    1416      76

可以看到,静态调用占用的内存与 源码方式是一样的,这个也能证明静态调用的特点。

3.4 隐性动态调用

将共享库编译成libcalculate.so,然后我们在测试程序中,引用动态库头文件,编译,同时将动态库拷贝到/usr/lib/下,运行,监控如下:

ubuntu@VM-0-17-ubuntu:~$ ps -ef|grep test-hid
ubuntu    5433  3082  0 11:13 pts/3    00:00:00 ./test-hid
ubuntu    5480  3194  0 11:13 pts/4    00:00:00 grep test-hid
ubuntu@VM-0-17-ubuntu:~$ pmap -x 5433
5433:   ./test-hid
Address           Kbytes     RSS   Dirty Mode  Mapping
00005564e6e88000       4       4       0 r-x-- test-hid
00005564e6e88000       0       0       0 r-x-- test-hid
00005564e7088000       4       4       4 r---- test-hid
00005564e7088000       0       0       0 r---- test-hid
00005564e7089000       4       4       4 rw--- test-hid
00005564e7089000       0       0       0 rw--- test-hid
00005564e79d1000     132       4       4 rw---   [ anon ]
00005564e79d1000       0       0       0 rw---   [ anon ]
00007f64bfd05000    1948    1068       0 r-x-- libc-2.27.so
00007f64bfd05000       0       0       0 r-x-- libc-2.27.so
00007f64bfeec000    2048       0       0 ----- libc-2.27.so
00007f64bfeec000       0       0       0 ----- libc-2.27.so
00007f64c00ec000      16      16      16 r---- libc-2.27.so
00007f64c00ec000       0       0       0 r---- libc-2.27.so
00007f64c00f0000       8       8       8 rw--- libc-2.27.so
00007f64c00f0000       0       0       0 rw--- libc-2.27.so
00007f64c00f2000      16      12      12 rw---   [ anon ]
00007f64c00f2000       0       0       0 rw---   [ anon ]
00007f64c00f6000       4       4       0 r-x-- libcalculate.so
00007f64c00f6000       0       0       0 r-x-- libcalculate.so
00007f64c00f7000    2044       0       0 ----- libcalculate.so
00007f64c00f7000       0       0       0 ----- libcalculate.so
00007f64c02f6000       4       4       4 r---- libcalculate.so
00007f64c02f6000       0       0       0 r---- libcalculate.so
00007f64c02f7000       4       4       4 rw--- libcalculate.so
00007f64c02f7000       0       0       0 rw--- libcalculate.so
00007f64c02f8000     164     160       0 r-x-- ld-2.27.so
00007f64c02f8000       0       0       0 r-x-- ld-2.27.so
00007f64c0512000      20      12      12 rw---   [ anon ]
00007f64c0512000       0       0       0 rw---   [ anon ]
00007f64c0521000       4       4       4 r---- ld-2.27.so
00007f64c0521000       0       0       0 r---- ld-2.27.so
00007f64c0522000       4       4       4 rw--- ld-2.27.so
00007f64c0522000       0       0       0 rw--- ld-2.27.so
00007f64c0523000       4       4       4 rw---   [ anon ]
00007f64c0523000       0       0       0 rw---   [ anon ]
00007ffc8b435000     132      12      12 rw---   [ stack ]
00007ffc8b435000       0       0       0 rw---   [ stack ]
00007ffc8b4ef000      12       0       0 r----   [ anon ]
00007ffc8b4ef000       0       0       0 r----   [ anon ]
00007ffc8b4f2000       8       4       0 r-x--   [ anon ]
00007ffc8b4f2000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            6588    1332      92

上述监控可以看到,内存使用基本上没有太大变化,不过内存中已经有了 libcalculate.so 了。

3.5 显性动态调用

显性动态调用测试代码如下:

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>

#define LIB_CALCULATE_PATH  "./tmp/libcalculate.so"

typedef int (*CALC_FUNC)(int, int);

typedef void (*CALC_FUNC1)(void);

int main(void)
{
    void *handle;
    char *error;
    CALC_FUNC calc_func = NULL;    
    CALC_FUNC1 print_func = NULL;

    printf("start wait 60s...\n");
    sleep(60);
    printf("will return in 20...\n");

    handle = dlopen(LIB_CALCULATE_PATH, RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        return -1;
    }

    dlerror();

    *(void **) (&calc_func) = dlsym(handle, "add");
    if ((error = dlerror()) != NULL)  {
        fprintf(stderr, "%s\n", error);
        return -1;
    }
    
    printf("add: %d\n", (*calc_func)(2,7));

    print_func = (CALC_FUNC1)dlsym(handle, "print_CA_info");
    print_func();

    sleep(20);
    return 0;
}

编译、运行、监控如下:

ubuntu@VM-0-17-ubuntu:~$ ps -ef|grep test-obvious
ubuntu    6139  3082  0 11:18 pts/3    00:00:00 ./test-obvious
ubuntu    6156  3194  0 11:18 pts/4    00:00:00 grep test-obvious
ubuntu@VM-0-17-ubuntu:~$ pmap -x 6139
6139:   ./test-obvious
Address           Kbytes     RSS   Dirty Mode  Mapping
00005561450f1000       4       4       0 r-x-- test-obvious
00005561450f1000       0       0       0 r-x-- test-obvious
00005561452f2000       4       4       4 r---- test-obvious
00005561452f2000       0       0       0 r---- test-obvious
00005561452f3000       4       4       4 rw--- test-obvious
00005561452f3000       0       0       0 rw--- test-obvious
00005561459a5000     132       4       4 rw---   [ anon ]
00005561459a5000       0       0       0 rw---   [ anon ]
00007f1c0abc2000    1948    1080       0 r-x-- libc-2.27.so
00007f1c0abc2000       0       0       0 r-x-- libc-2.27.so
00007f1c0ada9000    2048       0       0 ----- libc-2.27.so
00007f1c0ada9000       0       0       0 ----- libc-2.27.so
00007f1c0afa9000      16      16      16 r---- libc-2.27.so
00007f1c0afa9000       0       0       0 r---- libc-2.27.so
00007f1c0afad000       8       8       8 rw--- libc-2.27.so
00007f1c0afad000       0       0       0 rw--- libc-2.27.so
00007f1c0afaf000      16      12      12 rw---   [ anon ]
00007f1c0afaf000       0       0       0 rw---   [ anon ]
00007f1c0afb3000      12      12       0 r-x-- libdl-2.27.so
00007f1c0afb3000       0       0       0 r-x-- libdl-2.27.so
00007f1c0afb6000    2044       0       0 ----- libdl-2.27.so
00007f1c0afb6000       0       0       0 ----- libdl-2.27.so
00007f1c0b1b5000       4       4       4 r---- libdl-2.27.so
00007f1c0b1b5000       0       0       0 r---- libdl-2.27.so
00007f1c0b1b6000       4       4       4 rw--- libdl-2.27.so
00007f1c0b1b6000       0       0       0 rw--- libdl-2.27.so
00007f1c0b1b7000     164     164       0 r-x-- ld-2.27.so
00007f1c0b1b7000       0       0       0 r-x-- ld-2.27.so
00007f1c0b3d1000      20      12      12 rw---   [ anon ]
00007f1c0b3d1000       0       0       0 rw---   [ anon ]
00007f1c0b3e0000       4       4       4 r---- ld-2.27.so
00007f1c0b3e0000       0       0       0 r---- ld-2.27.so
00007f1c0b3e1000       4       4       4 rw--- ld-2.27.so
00007f1c0b3e1000       0       0       0 rw--- ld-2.27.so
00007f1c0b3e2000       4       4       4 rw---   [ anon ]
00007f1c0b3e2000       0       0       0 rw---   [ anon ]
00007fffe6879000     132      16      16 rw---   [ stack ]
00007fffe6879000       0       0       0 rw---   [ stack ]
00007fffe69a7000      12       0       0 r----   [ anon ]
00007fffe69a7000       0       0       0 r----   [ anon ]
00007fffe69aa000       8       4       0 r-x--   [ anon ]
00007fffe69aa000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            6596    1360      96
ubuntu@VM-0-17-ubuntu:~$ pmap -x 6139
6139:   ./test-obvious
Address           Kbytes     RSS   Dirty Mode  Mapping
00005561450f1000       4       4       0 r-x-- test-obvious
00005561450f1000       0       0       0 r-x-- test-obvious
00005561452f2000       4       4       4 r---- test-obvious
00005561452f2000       0       0       0 r---- test-obvious
00005561452f3000       4       4       4 rw--- test-obvious
00005561452f3000       0       0       0 rw--- test-obvious
00005561459a5000     132       4       4 rw---   [ anon ]
00005561459a5000       0       0       0 rw---   [ anon ]
00007f1c0a9c0000       4       4       0 r-x-- libcalculate.so
00007f1c0a9c0000       0       0       0 r-x-- libcalculate.so
00007f1c0a9c1000    2044       0       0 ----- libcalculate.so
00007f1c0a9c1000       0       0       0 ----- libcalculate.so
00007f1c0abc0000       4       4       4 r---- libcalculate.so
00007f1c0abc0000       0       0       0 r---- libcalculate.so
00007f1c0abc1000       4       4       4 rw--- libcalculate.so
00007f1c0abc1000       0       0       0 rw--- libcalculate.so
00007f1c0abc2000    1948    1272       0 r-x-- libc-2.27.so
00007f1c0abc2000       0       0       0 r-x-- libc-2.27.so
00007f1c0ada9000    2048       0       0 ----- libc-2.27.so
00007f1c0ada9000       0       0       0 ----- libc-2.27.so
00007f1c0afa9000      16      16      16 r---- libc-2.27.so
00007f1c0afa9000       0       0       0 r---- libc-2.27.so
00007f1c0afad000       8       8       8 rw--- libc-2.27.so
00007f1c0afad000       0       0       0 rw--- libc-2.27.so
00007f1c0afaf000      16      12      12 rw---   [ anon ]
00007f1c0afaf000       0       0       0 rw---   [ anon ]
00007f1c0afb3000      12      12       0 r-x-- libdl-2.27.so
00007f1c0afb3000       0       0       0 r-x-- libdl-2.27.so
00007f1c0afb6000    2044       0       0 ----- libdl-2.27.so
00007f1c0afb6000       0       0       0 ----- libdl-2.27.so
00007f1c0b1b5000       4       4       4 r---- libdl-2.27.so
00007f1c0b1b5000       0       0       0 r---- libdl-2.27.so
00007f1c0b1b6000       4       4       4 rw--- libdl-2.27.so
00007f1c0b1b6000       0       0       0 rw--- libdl-2.27.so
00007f1c0b1b7000     164     164       0 r-x-- ld-2.27.so
00007f1c0b1b7000       0       0       0 r-x-- ld-2.27.so
00007f1c0b3d1000      20      12      12 rw---   [ anon ]
00007f1c0b3d1000       0       0       0 rw---   [ anon ]
00007f1c0b3e0000       4       4       4 r---- ld-2.27.so
00007f1c0b3e0000       0       0       0 r---- ld-2.27.so
00007f1c0b3e1000       4       4       4 rw--- ld-2.27.so
00007f1c0b3e1000       0       0       0 rw--- ld-2.27.so
00007f1c0b3e2000       4       4       4 rw---   [ anon ]
00007f1c0b3e2000       0       0       0 rw---   [ anon ]
00007fffe6879000     132      16      16 rw---   [ stack ]
00007fffe6879000       0       0       0 rw---   [ stack ]
00007fffe69a7000      12       0       0 r----   [ anon ]
00007fffe69a7000       0       0       0 r----   [ anon ]
00007fffe69aa000       8       4       0 r-x--   [ anon ]
00007fffe69aa000       0       0       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
ffffffffff600000       0       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB            8652    1564     104

上面的监控信息我们可以清楚的看到:

  • 在显性调用中,dlopen之前, libcalculate.so并没有读入到内存中,但是因为使用了插件机制,将libdl-2.27.so 插件库读入内存了,也是因为这个原因,导致内存并没有想象中的那么小。
  • dlopen之后,libcalculate.so 被读入内存中,内存也增加到了1564kb。

3.6 内存对比

方式内存
源码1416Kb
静态库1416Kb
隐性动态库1332
显性动态库调用前1360Kb/调用后1564Kb

小结

  • 显性调用更多的是体现在“插件”的思想,使用起来更加灵活,比如大的工程项目中,同样一套代码,提供不一样的功能时,为了节省内存、磁盘容量,可以按需加载。
  • 在使用方式上,显性调用相比隐性调用,略复杂,需要增加额外的转换代码,而隐性调用,只需要包含动态库头文件,在代码中,直接调用API即可。
  • 在生产程序中,如果对内存或磁盘、启动速度没有严苛的要求,尽量使用隐形调用,方便程序编写和维护。

(523条消息) 深入分析linux下 动态库的显性调用(dlopen)和隐性调用区别_猪哥-嵌入式的博客-CSDN博客_linux动态库调用

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
文中是linux下 C++动态库 实现接口提供类导出的一个例子 注意其中使用函数返回基类指针的用法,因为Linux的动态链接库不能像MFC中那样直接导出类 一、介绍 如何使用dlopen API动态地加载C++函数和类,是Unix C++程序员经常碰到的问题。 事实上,情况偶尔有些复杂,需要一些解释。这正是写这篇mini HOWTO的缘由。 理解这篇文档的前提是对C/C++语言中dlopen API有基本的了解。 这篇HOWTO的维护链接是: http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 二、问题所在 有时你想在运行时加载一个库(并使用其中的函数),这在你为你的程序写一些插件或模块架构的时候经常发生。 在C语言中,加载一个库轻而易举(调用dlopen、dlsym和dlclose就够了),但对C++来说,情况稍微复杂。 动态加载一个C++库的困难一部分是因为C++的name mangling (译者注:也有人把它翻译为“名字毁坏”,我觉得还是不翻译好), 另一部分是因为dlopen API是用C语言实现的,因而没有提供一个合适的方式来装载类。 在解释如何装载C++库之前,最好再详细了解一下name mangling。 我推荐您了解一下它,即使您对它不感兴趣。因为这有助于您理解问题是如何产生的,如何才能解决它们。 1. Name Mangling 在每个C++程序(或库、目标文件)中, 所有非静态(non-static)函数在二进制文件中都是以“符号(symbol)”形式出现的。 这些符号都是唯一的字符串,从而把各个函数在程序、库、目标文件中区分开来。 在C中,符号名正是函数名:strcpy函数的符号名就是“strcpy”,等等。 这可能是因为两个非静态函数的名字一定各不相同的缘故。 而C++允许重载(不同的函数有相同的名字但不同的参数), 并且有很多C所没有的特性──比如类、成员函数、异常说明──几乎不可能直接用函数名作符号名。 为了解决这个问题,C++采用了所谓的name mangling。它把函数名和一些信息(如参数数量和大小)杂糅在一起, 改造成奇形怪状,只有编译器才懂的符号名。 例如,被mangle后的foo可能看起来像foo@4%6^,或者,符号名里头甚至不包括“foo”。 其中一个问题是,C++标准(目前是[ISO14882])并没有定义名字必须如何被mangle, 所以每个编译器都按自己的方式来进行name mangling。 有些编译器甚至在不同版本间更换mangling算法(尤其是g++ 2.x和3.x)。 即使您搞清楚了您的编译器到底怎么进行mangling的,从而可以用dlsym调用函数了, 但可能仅仅限于您手头的这个编译器而已,而无法在下一版编译器下工作。 三、类 使用dlopen API的另一个问题是,它只支持加载函数。 但在C++中,您可能要用到库中的一个类,而这需要创建该类的一个实例,这不容易做到。 四、解决方案 1. extern "C" C++有个特定的关键字用来声明采用C binding的函数: extern "C" 。 用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。 因此,只有非成员函数才能被声明为extern "C",并且不能被重载。 尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。 冠以extern "C"限定符后,并不意味着函数中无法使用C++代码了, 相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种类型的参数。
Linux中,Qt Creator是一个强大的集成开发环境,用于开发跨平台的应用程序。在使用Qt Creator创建和调用动态库时,需要经过以下几个步骤: 1. 首先,在Qt Creator中新建一个工程。选择“Dynamic Library”作为项目类型。 2. 在工程文件中,定义需要暴露给其他程序使用的函数和类。可以在.h头文件中声明函数和类的接口,并在.cpp源文件中实现相应的功能。 3. 编译生成动态库文件。在Qt Creator中,可以点击“构建”按钮编译和链接生成动态库文件。生成的动态库文件一般以.so(shared object)为扩展名。 4. 创建一个新的可执行程序项目,并引用该动态库。在新的项目中,需要在.pro文件中添加对动态库的依赖关系。例如,可以使用LIBS += -L/path/to/library -lmylibrary来指定动态库的路径和名称。 5. 在可执行程序中调用动态库中的函数或类。在主函数或其他需要使用动态库的地方,可以直接调用动态库中定义的函数或类,实现相应的功能。 值得注意的是,动态库调用中还需要注意以下几点: 1. 在调用动态库函数时,需要先加载动态库。可以使用dlopen函数加载动态库文件,并使用dlsym函数获取需要调用的函数指针。 2. 调用动态库中的函数时,需要根据函数的参数类型进行适当的类型转换。因为动态库函数的参数类型可能与调用者的类型不完全匹配。 3. 在完成动态库的使用后,需要使用dlclose函数关闭对动态库的引用,释放相关资源。 总结来说,使用Qt Creator在Linux中创建和调用动态库需要进行项目的设置、编译生成动态库文件,然后在其他项目中引用动态库调用其中定义的函数或类。同时,还需要注意动态库的加载和关闭过程,以确保正确使用动态库功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值