卸载共享库中的ctypes中的共享库

卸载共享库中的ctypes中的共享库,第1张

卸载共享库中的ctypes中的共享库

始终遵循 “自己清洁后清理 ”的规则(尽管现代技术会为您提供清洁方面的帮助)。

[Python 3.5]:ctypes-
Python的外部函数库
包含许多有用的信息,应该成为您的朋友。

ctypes 使用 dlopen whel加载 .dll 。正如我注意到的那样,它 没有 调用相应的 dlclose, 这意味着
.dll (以及 在加载 .dll 时加载的所有从属文件 )将保留在内存中,直到进程终止(或直到​​明确卸载)为止。

来自[man7]:DLOPEN(3):

如果 文件名
指定的对象具有其他共享库的依赖关系,则动态链接程序也会使用相同的规则自动加载这些共享库。(如果这些对象又具有依赖关系,则该过程可能会递归发生,依此类推。)

如果使用 dlopen() 再次加载相同的共享对象,则返回相同的对象句柄。动态连接器保持参考计数对象句柄,因此一个动态加载共享对象不释放直到
dlclose() 被调用在其上多次 dlopen()的 成功就可以了。任何初始化返回(见下文)仅被调用一次。

因此,我认为您不会有问题(当然,一切都取决于上下文)。如您所见,多次加载一个库实际上并不会每次都加载,因此内存不足的机会非常小(除非您加载大量不同的
.dll ,每个 .dll 都有很多不同的依赖项)。

一种情况下,我能想到的是加载一个 .dll文件 ,它使用一个符号从另一个 .dll文件 。如果符号在另一个(也定义 3 次.DLL
,这是之前加载,则代码将表现与预期不同。

无论如何,您可以手动卸载(或更好:减少其 refcount )一个 .dll (我不确定这是否适合 建议的方式最佳做法
),如下面的示例所示。

dll.c

#include <stdio.h>int test() {    printf("[%s] (%d) - [%s]n", __FILE__, __LINE__, __FUNCTION__);    return 0;}

pre.py

import sysfrom ctypes import CDLL,     c_int, c_void_pDLL = "./dll.so"dlclose_func = CDLL(None).dlclose  # This WON'T work on Windlclose_func.argtypes = [c_void_p]def _load_dll(dll_name):    dll_dll = CDLL(dll_name)    print("{:}".format(dll_dll))    return dll_dlldef _load_test_func(dll):    test_func = dll.test    test_func.restype = c_int    return test_funcdef main():    print("Loading a dll via `ctypes`, then delete the object. The dll is not unloaded. Call `dlclose` to unload. A 2nd call will fail.")    dll_dll = _load_dll(DLL)    dll_handle = dll_dll._handle    del dll_dll    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll_handle)))  # Even if the ctypes dll object was destroyed, the dll wasn't unloaded    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll_handle)))  # A new dlclose call will fail    print("nUse `ctypes` to load the dll twice. The dll is not actually loaded only the 1st time (both have the same handle), but its ref count is increased. `dlclose` must be also called twice.")    dll0_dll = _load_dll(DLL)    dll1_dll = _load_dll(DLL)    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll0_dll._handle)))    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll1_dll._handle)))    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll1_dll._handle)))    print("nLoad a dll via `ctypes`, and load one of its funcs. Try calling it before and after unloading the dll.")    dll_dll = _load_dll(DLL)    test_func = _load_test_func(dll_dll)    print("{:} returned {:d}".format(test_func.__name__, test_func()))    print("{:} returned {:d}".format(dlclose_func.__name__, dlclose_func(dll_dll._handle)))    print("{:} returned {:d}".format(test_func.__name__, test_func()))  # Comment this line as it would segfault !!!if __name__ == "__main__":    print("Python {:s} on {:s}n".format(sys.version, sys.platform))    main()

输出

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q052179325]> lspre.py  dll.c[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q052179325]> gcc -fPIC

-shared -o dll.so dll.c
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q052179325]> python3
./pre.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux

Loading a dll via `ctypes`, then delete the object. The dll is not

unloaded. Call

dlclose
to unload. A 2nd call will fail.

dlclose returned 0
dlclose returned -1

Use `ctypes` to load the dll twice. The dll is not actually loaded only

the 1st time (both have the same handle), but its ref count is increased.

dlclose
must be also called twice.


dlclose returned 0
dlclose returned 0
dlclose returned -1

Load a dll via `ctypes`, and load one of its funcs. Try calling it

before and after unloading the dll.

[dll.c] (5) - [test]
test returned 0
dlclose returned 0
Segmentation fault (core dumped)



欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5632485.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存