dlopen重复打开的一些问题

dlopen重复打开的一些问题

源码地址: https://gitee.com/layty/test-dlopen
如果打开多个动态库(软连接的),会共享内存吗?

结论: 会

如果动态库更新了,不close,直接open,会更新吗?

结论: 不会,要先close,再open即可

动态库源码如下

#include <iostream>
extern "C"{
void say_hello(){
    static int i=0;
    std::cout << "Hello, from dlopen!" << i++ << std::endl;
}
}

一个动态库打开多次

结论:同一个句柄,这个直接在man手册有讲的

#include <iostream>
#include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose
typedef void(*say_hello)(void);
const char* dllPath = "./libdlopen.so";
int main()
{
    for(int i=0;i<10;i++)
    {
        void* handle = dlopen( dllPath, RTLD_LAZY );
        if( !handle )
        {
            fprintf( stderr, "[%s](%d) dlopen get error: %s\n", __FILE__, __LINE__, dlerror() );
            exit( EXIT_FAILURE );
        }
        else
        {
            std::cout << "handle addr is " << handle << std::endl;
        }
        say_hello fun = (say_hello)dlsym( handle, "say_hello" );
        //std::cout << "handle addr is close " << handle << std::endl;
        //dlclose(handle);
    }
}

输出

layty@ubuntu:~/work/Test/dlopen/build$ ./main1
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0
handle addr is 0x55692beb3ed0

如果是关闭后重新打开呢

//std::cout << "handle addr is close " << handle << std::endl;
//dlclose(handle);

输出还是

handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed0
handle addr is 0x55725a3eaed0
handle addr is close 0x55725a3eaed

使用软连接创建多个动态库

结论: 唯一的句柄,内存共享

layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.2.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.3.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.4.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.5.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.6.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.7.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.8.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.9.so
layty@ubuntu:~/work/Test/dlopen/build$ ln -s libdlopen.so libdlopen.so.0.so

然后直接多次打开

#include <iostream>
#include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose


typedef void(*say_hello)(void);
const char* dllPath = "./libdlopen.so";

int main()
{
    for(int i=0;i<10;i++)
    {
        char dllPathsoft[100];
        snprintf(dllPathsoft,sizeof(dllPathsoft),"%s.%d.so",dllPath,i);

        void* handle = dlopen( dllPathsoft, RTLD_LAZY );
        if( !handle )
        {
            
            fprintf( stderr, "[%s](%d)@%s dlopen get error: %s\n", __FILE__, __LINE__, dllPathsoft,dlerror() );
            exit( EXIT_FAILURE );
        }
        else
        {
            std::cout << "handle addr is " << handle << std::endl;
        }
        say_hello fun = (say_hello)dlsym( handle, "say_hello" );
        //std::cout << "handle addr is close " << handle << std::endl;
        // dlclose(handle);
    }
}

输出

handle addr is 0x55acb4ee8ed0
Hello, from dlopen!0
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!1
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!2
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!3
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!4
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!5
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!6
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!7
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!8
handle addr is 0x55acb4ee8ed0
Hello, from dlopen!9

如果中间close了呢

内存映射的句柄还是一样,但是变量已经被释放了

layty@ubuntu:~/work/Test/dlopen/build$ ./main4
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0
handle addr is 0x55d04e7bbed0
Hello, from dlopen!0
handle addr is close 0x55d04e7bbed0

复制动态库

结论: 会有不同的地址映射

cp  libdlopen.so libdlopen.so.10.so
cp  libdlopen.so libdlopen.so.11.so
cp  libdlopen.so libdlopen.so.12.so
cp  libdlopen.so libdlopen.so.13.so
cp  libdlopen.so libdlopen.so.14.so
cp  libdlopen.so libdlopen.so.15.so
cp  libdlopen.so libdlopen.so.16.so
cp  libdlopen.so libdlopen.so.17.so
cp  libdlopen.so libdlopen.so.18.so
cp  libdlopen.so libdlopen.so.19.so

测试代码

#include <iostream>
#include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose


typedef void(*say_hello)(void);
const char* dllPath = "./libdlopen.so";

int main()
{
    for(int i=10;i<20;i++)
    {
        char dllPathsoft[100];
        snprintf(dllPathsoft,sizeof(dllPathsoft),"%s.%d.so",dllPath,i);

        void* handle = dlopen( dllPathsoft, RTLD_LAZY );
        if( !handle )
        {
            
            fprintf( stderr, "[%s](%d)@%s dlopen get error: %s\n", __FILE__, __LINE__, dllPathsoft,dlerror() );
            exit( EXIT_FAILURE );
        }
        else
        {
            std::cout << "handle addr is " << handle << std::endl;
        }
        say_hello fun = (say_hello)dlsym( handle, "say_hello" );
        fun();
        //std::cout << "handle addr is close " << handle << std::endl;
        // dlclose(handle);
    }
}

输出

layty@ubuntu:~/work/Test/dlopen/build$ ./main5 
handle addr is 0x55e15ac76ed0
Hello, from dlopen!0
handle addr is 0x55e15ac77940
Hello, from dlopen!0
handle addr is 0x55e15ac77fa0
Hello, from dlopen!0
handle addr is 0x55e15ac78600
Hello, from dlopen!0
handle addr is 0x55e15ac78c60
Hello, from dlopen!0
handle addr is 0x55e15ac792c0
Hello, from dlopen!0
handle addr is 0x55e15ac79920
Hello, from dlopen!0
handle addr is 0x55e15ac79f80
Hello, from dlopen!0
handle addr is 0x55e15ac7a5e0
Hello, from dlopen!0
handle addr is 0x55e15ac7ac40
Hello, from dlopen!0

如果复制之后关闭呢

可以看到句柄是一样的

layty@ubuntu:~/work/Test/dlopen/build$ ./main6
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0
handle addr is 0x564ba76c4ed0
Hello, from dlopen!0
handle addr is close 0x564ba76c4ed0

动态更新动态库

main7不close直接open 不会更新,也应该这样,否则内存什么的怎么处理

再写一个so

#include <iostream>

extern "C"{

void say_hello(){
    static int i=0;
    std::cout << "Hello, from dlopen new!" << i++ << std::endl;
}

}

测试的源码

#include <iostream>
#include <dlfcn.h>    // dlopen, dlerror, dlsym, dlclose


typedef void(*say_hello)(void);
const char* dllPath = "./libdlopen.so.main7.so";

int main()
{
    for(int i=0;i<2;i++)
    {
        void* handle = dlopen( dllPath, RTLD_LAZY );
        if( !handle )
        {
            fprintf( stderr, "[%s](%d) dlopen get error: %s\n", __FILE__, __LINE__, dlerror() );
            exit( EXIT_FAILURE );
        }
        else
        {
            std::cout << "handle addr is " << handle << std::endl;
        }
        say_hello fun = (say_hello)dlsym( handle, "say_hello" );
        std::cout << "handle addr is close " << handle << std::endl;
        fun();
        
        std::cout << "wait to replace so " << handle << std::endl;
        getchar();
        dlclose(handle);
    }
}

执行如下

ln -sf libdlopen.so  ./libdlopen.so.main7.so

ln -sf libdlopen2.so  ./libdlopen.so.main7.so


layty@ubuntu:~/work/Test/dlopen/build$ ./main7 
handle addr is 0x55a2dd4f7ed0
handle addr is close 0x55a2dd4f7ed0
Hello, from dlopen!0
wait to replace so 0x55a2dd4f7ed0
----------------------------------------------------------------使用软连接换掉so
handle addr is 0x55a2dd4f7ed0
handle addr is close 0x55a2dd4f7ed0
Hello, from dlopen!1
wait to replace so 0x55a2dd4f7ed0

使用close再去打开main8

 ln -sf libdlopen2.so  
layty@ubuntu:~/work/Test/dlopen/build$ ./main8
handle addr is 0x55fec2ce8ed0
handle addr is close 0x55fec2ce8ed0
Hello, from dlopen!0
wait to replace so 0x55fec2ce8ed0
--------------------------------------------------这个地方使用 新开一个终端执行ln -sf libdlopen2.so  ./libdlopen.so.main7.so
handle addr is 0x55fec2ce8ed0
handle addr is close 0x55fec2ce8ed0
Hello, from dlopen new!0-----------------------------可以看到so使用新的,类似于热更新了
wait to replace so 0x55fec2ce8ed0
posted @ 2022-06-27 14:12  zongzi10010  阅读(1948)  评论(0编辑  收藏  举报