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动态库调用