Używam moduł ctypes
w Pythonie, aby załadować wspólną c-biblioteka, która zawiera pamięć lokalna wątku. Jest to dość duża biblioteka c z długą historią, którą staramy się uczynić wątkiem bezpiecznym. Biblioteka zawiera wiele zmiennych globalnych i statyki, więc naszą początkową strategią w zakresie bezpieczeństwa wątków było użycie lokalnego magazynu wątków. Chcemy, aby nasz libarary był niezależny od platformy i kompilował i testował bezpieczeństwo wątków zarówno na Win32, Win64, jak i 64-bitowym Ubuntu. Z czystego procesu c nie ma żadnych problemów.wyciek pamięci podczas korzystania z biblioteki współdzielonej pamięci lokalnej wątku poprzez ctypes w programie Pythona
Jednakże w pytona (2.6 i 2.7), na win32 i Ubuntu widzimy przecieków pamięci. Wygląda na to, że lokalny magazyn wątków nie jest poprawnie zwalniany po zakończeniu wątku python. A przynajmniej w jakiś sposób proces Pythona nie jest "świadomy" o tym, że pamięć jest wolna. Ten sam problem jest również postrzegane w C# -program na Win32 faktycznie, ale to nie jest obecny na naszym komputerze testowym serwerze Win64 (z systemem Pythona 2.7 też).
Problemem może być powielana z prostym przykładzie zabawek takich jak to:
Utwórz c-plik zawierający (na linux/unix
usunąć __declspec(dllexport)
):
#include <stdio.h>
#include <stdlib.h>
void __declspec(dllexport) Leaker(int tid){
static __thread double leaky[1024];
static __thread int init=0;
if (!init){
printf("Thread %d initializing.", tid);
int i;
for (i=0;i<1024;i++) leaky[i]=i;
init=1;}
else
printf("This is thread: %d\n",tid);
return;}
Kompilacja wit MINGW
na windows/gcc na linux jak:
gcc -o leaky.dll
(lub leaky.so
) -shared the_file.c
Z okien mogliśmy skompilowany z Visual Studio, zastępując __thread
z __declspec(thread)
. Jednak na win32 (do winXP wierzę), to nie działa, gdy biblioteka ma być ładowany w czasie pracy z LoadLibrary
.
Teraz stworzyć program Pythona jak:
import threading, ctypes, sys, time
NRUNS=1000
KEEP_ALIVE=5
REPEAT=2
lib=ctypes.cdll.LoadLibrary("leaky.dll")
lib.Leaker.argtypes=[ctypes.c_int]
lib.Leaker.restype=None
def UseLibrary(tid,repetitions):
for i in range(repetitions):
lib.Leaker(tid)
time.sleep(0.5)
def main():
finished_threads=0
while finished_threads<NRUNS:
if threading.activeCount()<KEEP_ALIVE:
finished_threads+=1
thread=threading.Thread(target=UseLibrary,args=(finished_threads,REPEAT))
thread.start()
while threading.activeCount()>1:
print("Active threads: %i" %threading.activeCount())
time.sleep(2)
return
if __name__=="__main__":
sys.exit(main())
to wystarczy do odtworzenia błędu. Jawnie zaimportuj śmieciarz, robiąc collect gc.collect()
przy uruchamianiu każdego nowego wątku nie pomaga.
Przez chwilę myślałem, że problem dotyczy niekompatybilnych runtime (python skompilowany z Visual Studio, moja biblioteka z MINGW
). Ale problem jest również na Ubuntu, ale nie na serwerze Win64, nawet gdy biblioteka jest cross skompilowany z MINGW
.
Mam nadzieję, że każdy może pomóc!
Pozdrawiam, Simon Kokkendorff, National Survey and Cadastre of Denmark.
zapoznaj znane błędy python http://bugs.python.org/issue6627 http://bugs.python.org/issue3757 –
mógłbyś uwolnić nieszczelne zmiennych na zakończenie wątku w C? –
to naprawić, spróbuj użyć malloc i za darmo, aby zainicjować i usunąć tablicę – pyCthon