2013-02-26 410 views
3

我正在使用ctypes將一些C函數從DLL公開到Python腳本。其中一個函數返回一個動態大小的字符數組,我希望能夠在Python中讀取這個數組的內容,但是當我完成它時,屬性句柄也會釋放數組的內存。Python ctypes.string_at釋放行爲

的C語言代碼:

... 

#ifdef __cplusplus 
extern "C" 
{ 
#endif 
    __declspec(dllexport) char * WINAPI get_str() 
    { 
     int str_len = ... // figure out how long it is gonna be and set it here 
     char *ary = (char *)malloc(sizeof(char) * str_len); 

     // populate the array 
     ... 

     ary[str_len - 1] = '\0'; 

     return ary; 
    } 

#ifdef __cplusplus 
} 
#endif 

我建立我的DLL,它複製到它會被發現的位置,然後有這樣的Python代碼:

import ctypes 

my_dll = ctypes.WinDLL("MyDLLName.dll") 

some_str = ctypes.string_at(my_dll.get_str()) 

print some_str 

此代碼的所有工作正常正如你所期望的那樣。我的問題是:因爲ctypes.string_at在指定的內存位置創建一個字符串,當some_str超出Python解釋器的範圍時,該內存是否會被垃圾收集,或者我是否需要手動釋放它?

+0

我可以有回答了我自己的問題......我寫了一個無限循環,讓它在重複調用my_dll.get_str()的同時運行,並觀察我在Windows中的內存使用情況,並且似乎繼續攀升。話雖如此,我仍然希望爲了理智的緣故具體回答。 – KSletmoe 2013-02-26 03:19:31

回答

4

string_at在新的內存位置創建一個新的Python字符串,完全獨立於調用的內存位置。

Python或ctypes無法猜測您的本機代碼返回的內容 - 就其而言,它只是一個數字(在這種情況下恰好是有效的指針)。因此,經驗法則是:如果您編寫分配內存的C代碼,則還應該編寫等效的C代碼以取消分配它 - 並使用Python代碼從Ctypes中調用釋放的C代碼。

對於這樣的快速腳本和示例,由於您知道這是一個簡單的分配字符串,因此您可以通過使用ctypes調用系統free函數直接從Python端釋放它。

也就是說,返回的指針存儲在一個Python VAR: (你可能會或可能它不是貓適當的ctypes指針類型),並運行string_at, 使用後:

pointer = my_dll.get_str() 
some_str = ctypes.string_at(pointer) 
# This is windows specific - 
# on Posix, one have to load "libc.so" and use "free" from there: 
ctypes.cdll.msvcrt.free(pointer) 
+0

謝謝!我想盡可能多;我只是想確定。 – KSletmoe 2013-02-26 03:33:12

+0

您是否檢查過在C字符串中創建的地址與Python指針完全相同?我有同樣的問題,我發現他們是不同的。 – FrauHahnhen 2015-01-12 16:33:23