我从我的python脚本中调用了一个so文件。据我所知,我真的不需要使用ctypes释放在python中打开的共享库。但是,在我的so文件代码中,它会停止另一个so文件并且不执行dlclose()。在这种情况下,从python端使用是否安全?我不是必须释放在ctypes中打开的共享库所以提交文件吗?
规则清理后总是适用(尽管现代技术为您处理清洁方面)。
[Python 3.5]: ctypes - A foreign function library for Python包含许多有用的信息,应该是你的朋友。
ctypes使用dlopen whel加载.dll。正如我注意到的,它没有调用相应的dlclose,这意味着.dll(及其加载时加载的所有依赖项)将保留在内存中,直到进程终止(或直到显式卸载)。
如果filename指定的对象依赖于其他共享对象,则动态链接器也会使用相同的规则自动加载这些对象。 (如果这些对象依次具有依赖性,则此过程可以递归地发生,等等。) ... 如果使用dlopen()再次加载相同的共享对象,则返回相同的对象句柄。动态链接器维护对象句柄的引用计数,因此动态加载的共享对象在释放dlclose()之前不会被释放,因为dlopen()已经成功执行了多次。任何初始化返回(见下文)都只调用一次。
所以,我不认为你有问题(当然,一切都取决于上下文)。正如您所注意到的,多次加载库实际上并不是每次都加载它,因此内存耗尽的可能性非常小(除非您加载大量不同的.dll,每个都有很多不同的依赖项) 。
我能想到的一个案例是加载一个使用另一个.dll符号的.dll。如果该符号也在之前加载的另一个(3rd).dll中定义,那么代码的行为将与预期的不同。
无论如何,您可以手动卸载(或更好地:减少其引用计数)a .dll(我不确定这是如何符合推荐的方法或最佳实践),如下例所示。
dll.c:
#include <stdio.h>
int test() {
printf("[%s] (%d) - [%s]\n", __FILE__, __LINE__, __FUNCTION__);
return 0;
}
code.朋友:
import sys
from ctypes import CDLL, \
c_int, c_void_p
DLL = "./dll.so"
dlclose_func = CDLL(None).dlclose # This WON'T work on Win
dlclose_func.argtypes = [c_void_p]
def _load_dll(dll_name):
dll_dll = CDLL(dll_name)
print("{:}".format(dll_dll))
return dll_dll
def _load_test_func(dll):
test_func = dll.test
test_func.restype = c_int
return test_func
def 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]> ls code.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 ./code.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. <CDLL './dll.so', handle 1d7aa20 at 0x7fa38715f240> 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. <CDLL './dll.so', handle 1de2c80 at 0x7fa38715f240> <CDLL './dll.so', handle 1de2c80 at 0x7fa38715f278> 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. <CDLL './dll.so', handle 1de39c0 at 0x7fa38715f8d0> [dll.c] (5) - [test] test returned 0 dlclose returned 0 Segmentation fault (core dumped)