तो मैं एक सी फ़ंक्शन लिखने की कोशिश कर रहा हूं जो एक numpy सरणी ऑब्जेक्ट स्वीकार करता है, डेटा निकालता है, कुछ जोड़तोड़ करता है और एक अन्य सी सरणी को एक numpy सरणी ऑब्जेक्ट के रूप में देता है। सब कुछ निर्बाध रूप से काम करता है और मैं पाइथन रैपर का उपयोग करता हूं जो पाइथन पक्ष पर आसान हेरफेर में मदद करता है। हालांकि, मुझे स्मृति रिसाव का सामना करना पड़ रहा है। मेरे पास डबल्स का आउटपुट पॉइंटर है जिसे मैं मॉलोक-एड करता हूं और जिसे मैं पाइथन सरणी ऑब्जेक्ट में कॉलिंग पायथन फ़ंक्शन पर वापस करने से ठीक पहले लपेटता हूं,

PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);

arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
return arr;

हालांकि, यह एक स्मृति रिसाव बनाता है, क्योंकि डेटा कभी मुक्त नहीं होता है और मैंने यह पता लगाने के लिए कुछ गुगल किया कि यह ऐसे अनुप्रयोगों में एक समस्या है और समाधान गैर-तुच्छ है। इस पर मुझे जो सबसे उपयोगी संसाधन मिला वह है यहां दिया गया है। मैं विनाशक को लागू नहीं कर सका कि यह पृष्ठ दिए गए उदाहरण से बात करता है। क्या कोई इस में मेरी मदद कर सकता है? अधिक ठोस रूप से मैं कुछ ढूंढ रहा हूं,

PyObject *arr;
int nd = 2;
npy_intp dims[] = {5, 10};
double *data = some_function_that_returns_a_double_star(x, y, z);

arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
some_destructor_that_plug_memLeak_due_to_data_star(args);
return arr;
4
juneHunter 10 अक्टूबर 2018, 05:48

2 जवाब

सबसे बढ़िया उत्तर

लिंक में वर्णित तकनीक जो आपको समझ में नहीं आई वह एक अच्छी है: एक पायथन ऑब्जेक्ट बनाएं जो जानता है कि नष्ट होने पर आपकी मेमोरी को कैसे मुक्त किया जाए, और इसे लौटाए गए सरणी का आधार बनाएं।

ऐसा लगता है कि आप एक नया एक्सटेंशन प्रकार बनाने की जटिलता से अभिभूत हो गए हैं। सौभाग्य से, यह आवश्यक नहीं है। पायथन एक प्रकार के साथ आता है जिसे नष्ट होने पर मनमाने ढंग से सी-लेवल क्लीनअप करने के लिए डिज़ाइन किया गया है: कैप्सूल a>, जो एक पॉइंटर और एक डिस्ट्रक्टर फ़ंक्शन को एक साथ बंडल करता है और कैप्सूल के नष्ट होने पर डिस्ट्रक्टर को कॉल करता है।

आपकी मेमोरी के लिए एक कैप्सूल बनाने के लिए, सबसे पहले, हम एक डिस्ट्रक्टर फंक्शन को परिभाषित करते हैं:

void capsule_cleanup(PyObject *capsule) {
    void *memory = PyCapsule_GetPointer(capsule, NULL);
    // I'm going to assume your memory needs to be freed with free().
    // If it needs different cleanup, perform whatever that cleanup is
    // instead of calling free().
    free(memory);
}

और आप अपने सरणी के आधार के रूप में एक कैप्सूल सेट करते हैं

PyObject *capsule = PyCapsule_New(data, NULL, capsule_cleanup);
PyArray_SetBaseObject((PyArrayObject *) arr, capsule);
// Do not Py_DECREF the capsule; PyArray_SetBaseObject stole your
// reference.

और यह सुनिश्चित करना चाहिए कि आपकी मेमोरी एक बार उपयोग में न होने के बाद मुक्त हो जाए।

6
user2357112 supports Monica 10 अक्टूबर 2018, 04:19

जबकि PyCapsule दृष्टिकोण अधिक सामान्य रूप से काम करता है, जब आप OWNDATA ध्वज सेट करके कचरा एकत्र करते हैं तो आप अपने लिए सरणी में स्मृति को मुक्त करने के लिए numpy प्राप्त कर सकते हैं।

double *data = some_function_that_returns_a_double_star(x, y, z);
PyObject *arr = PyArray_SimpleNewFromData(nd, dims, NPY_DOUBLE, (void *)data);
PyArray_ENABLEFLAGS((PyArrayObject*) arr, NPY_ARRAY_OWNDATA);
3
Robin Betz 18 सितंबर 2019, 21:43