- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在分析以下代码,它可以正确编译和运行,但会产生内存泄漏。
cfiboheap
是 Fibonacci 堆的 C 实现,以下代码是 cfiboheap
的 Cython 包装器(其中的一部分)。
我的疑虑是从插入函数开始的。对象 data
已在某处创建并传递给函数 insert()
。由于该函数想要将此对象添加到 fiboheap,因此它增加了它的引用计数。但之后呢?所有权归谁所有?在我的理解中,C 函数 fh_insertkey()
只是借用了所有权。然后返回一个需要封装的专有指针,再由insert()
返回。凉爽的。但是我的对象 data
及其引用计数?通过创建胶囊,我创建了一个新对象,但我并没有减少 data
的引用计数。这会产生内存泄漏。
(请注意,在 insert()
返回之前注释掉 Py_INCREF
或添加 Py_DECREF
会导致段错误。)
我的问题是:
1) 为什么在 insert()
期间需要增加 data
的引用计数?
2) 为什么在 extract()
期间不需要使用 Py_DECREF
?
3) 更一般地说,在 C 和 Python 之间跳转时如何准确跟踪引用所有权?
4) 如何正确地释放像 FiboHeap 这样的对象?我是否应该在 __dealloc__()
中预防性地使用 Py_XDECREF
,如果是,如何使用?
谢谢!
cimport cfiboheap
from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer
from python_ref cimport Py_INCREF, Py_DECREF
cdef inline object convert_fibheap_el_to_pycapsule(cfiboheap.fibheap_el* element):
return PyCapsule_New(element, NULL, NULL)
cdef class FiboHeap:
def __cinit__(FiboHeap self):
self.treeptr = cfiboheap.fh_makekeyheap()
if self.treeptr is NULL:
raise MemoryError()
def __dealloc__(FiboHeap self):
if self.treeptr is not NULL:
cfiboheap.fh_deleteheap(self.treeptr)
cpdef object insert(FiboHeap self, double key, object data=None):
Py_INCREF(data)
cdef cfiboheap.fibheap_el* retValue = cfiboheap.fh_insertkey(self.treeptr, key, <void*>data)
if retValue is NULL:
raise MemoryError()
return convert_fibheap_el_to_pycapsule(retValue)
cpdef object extract(FiboHeap self):
cdef void* ret = cfiboheap.fh_extractmin(self.treeptr)
if ret is NULL:
raise IndexError("FiboHeap is empty")
return <object> ret
cpdef object decrease_key(FiboHeap self, object element, double newKey):
cdef void* ret = cfiboheap.fh_replacekey(self.treeptr, convert_pycapsule_to_fibheap_el(element), newKey)
if ret is NULL:
raise IndexError("New Key is Bigger")
return <object> ret
请注意,这不是我写的,但我正在使用这个示例来更好地理解 obj 引用并阻止泄漏(因为我实际上正在使用代码)。
使用 FiboHeap
的主要代码(以及发生泄漏的地方)如下所示:
cdef dijkstra(Graph G, int start_idx, int end_idx):
cdef np.ndarray[object, ndim=1] fiboheap_nodes = np.empty([G.num_nodes], dtype=object) # holds all of our FiboHeap Nodes Pointers
Q = FiboHeap()
fiboheap_nodes[start_idx] = Q.insert(0, start_idx)
# Then occasionally:
Q.insert(...)
Q.decrease_key(...)
Q.extract()
return
extract
不是 peek,而是适当的 pop,因此它删除了 C fiboheap 中的 C 元素。
结论:data
的引用计数显然会导致内存泄漏,但为什么呢?以及如何阻止它?
最佳答案
1) 需要增加insert
中的引用计数,因为它的引用计数会在插入结束时自动减少。 Cython 不知道您正在存储该对象供以后使用。 (您可以检查生成的 C 代码以查看函数末尾的 DECREF
)。如果使用引用计数为 1 的对象(即 .insert(SomeObject())
)调用 insert
,则该对象将在没有 的插入结束时被销毁>增加
2) 如果对象在 extract
期间从 cfiboheap
中移除,那么你应该做一个 DECREF
来确认你不再拿住。首先将它转换为对象(这样你仍然持有对它的引用)
cdef void* ret = cfiboheap.fh_extractmin(self.treeptr) # refcount is 1 here (from the INCREF when it was stored)
if ret==NULL:
# ...
ret_obj = <object>ret
# reference count should be 2 here - one for being on the heap and one for ret_obj. Casting to object increases the refcount in Cython
Py_DECREF(ret_obj) # 1 here
return ret_obj
3) 老实说,如果可以避免,请尽量不要使用 PyObject*
!让 Cython 来完成工作要好得多。如果无法避免,则只需确保在存储对象时调用一次 INCREF
,在停止存储对象时调用一次 DECREF
。
4) 您确实需要在 __dealloc__
中减少堆上剩余的对象。一个非常简单的方法可能是所有 extract
直到 cfiboheap
为空:
try:
while True:
self.extract()
except IndexError:
pass # ignore the error - we're done emptying the heap
关于胶囊使用的评论:谁拥有它们指向的 fibheap_el
(以及何时销毁)?如果它在 cfiboheap
被破坏时被破坏,那么你会遇到一个带有无效指针的胶囊仍然存在的问题。在某处使用这个胶囊可能会导致问题。如果它没有被 cfiboheap
破坏,那么您可能有另一个内存泄漏。
关于python - 令人困惑的引用所有权 : how to properly deallocate (via Py_DECREF) objects of an object?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38285729/
演讲的主题是 Objective-c 中的类和对象。我无法理解 [super dealloc] 的概念。我们有一些类 myClass,它继承自 NSObject。它有一些方法并从父类继承其他方法。所以
对于 ARC,有时我仍然需要编写一个 -dealloc 方法来进行一些清理。在极少数情况下,我需要引用实例的属性才能正确进行清理。例如从 NSNotificationCenter 中注销给定的发送者对
如果我有一个由 View Controller 控制的 View 堆栈,并且当我从 View 堆栈中弹出 View 时调用了 View 的 dealloc(包含 [super dealloc] )方法
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 9 年前。 Improve
当我的应用程序开始在我的自定义注释方法中崩溃时,我了解到我的内存有问题。我确信管理 map 的 viewcontroller 100% 应该已经从 View 堆栈中弹出。 这里是注释的代码,TaxiA
我刚刚一直在阅读有关如何正确地在 init 方法中失败的信息,并且文档似乎彼此不同意。一个建议抛出异常,而其他建议清理并返回 nil。当前的最佳做法是什么? 最佳答案 我相信普遍接受的做法是在失败时返
这是我的情况。这很复杂,所以请耐心等待。 我有一个 View 类,我们称它为 MyView。它创建一个加载指示器 subview ,然后启动将加载数据的后台操作。它还创建了一个 block ,后台队列
我正在设置 AMScrollingNavbar在 swift 。当我尝试转换时 - (void)dealloc { [self stopFollowingScrollView]; } 到 func
我正在尝试执行以下操作: 获得类'dealloc IMP 向所述类中注入(inject)一个自定义 IMP,它基本上调用原始的 dealloc IMP 当所述类的一个实例被释放时,两个 IMP 都应该
在我的一个 View Controller 中,它将自身添加为 UITextViewTextDidEndEditingNotification 通知的观察者,如下所示 [[NSNotification
我正在初始化一个对象,然后内联配置它。但是,不是在配置前一个实例(如果之前已分配)之前将其释放(在紧随其后的行中),而是推迟释放。因此,我对它所做的所有配置最终都成为一个已释放的对象 - 这当然不是我
是否需要将所有声明为IBOutlet的带有retain修饰符的@property设置为nil - (void)dealloc 方法?如果我不这样做,内存会被消耗/浪费吗? 假设自动引用计数关闭。 最佳
这是我在应用程序中切换 View 的方式: CGRect frame = self.view.frame; frame.origin.x = CGRectGetMaxX(frame);
假设有一个带有两个选项卡 A 和 B 的选项卡栏 Controller ,其中 A 是导航 Controller 。 当用户在A中时,他可以推送A1,然后推送A2,它们都是 View Controll
我有一个加载两个 View Controller 的 Root View 。例如:FirstVC、SecondVC。 当应用程序启动时,我将 FirstVC 显示为 Root View Control
我有一个基于导航的应用程序,可以在一些 ViewController 之间切换。如果我按下“goHome”按钮,方法 popViewControllerAnimated: 被调用,然后我返回到主屏幕。
我正在尝试调试为什么我的 dealloc 覆盖没有在我的一个 View Controller 上被调用。 我有一个通过 Storyboard设置的 View Controller 。我已经重写了所有
对于我的 iOS 7 应用,只想确认: dealloc 是否仍会被调用? 与是否开启ARC有关系吗? 最佳答案 是的,无论您是否使用 ARC,dealloc 都会在对象被释放时调用。 但是请注意,当您
我很难适应 C++ 处理动态和自动内存的方式。 我的问题: 指向自动分配实例的指针是否可以保留该实例解除分配,即使实例化范围已离开? 在this帖子我读到所有指向 dealloc 内存的指针都是无效的
我有三个 UIViewControllers,每当我关闭它们时,它们的所有 dealloc 方法都会被调用。这正是我想要发生的事情,这样内存就不会膨胀。 但是,当我运行配置文件来测试内存使用情况和一些
我是一名优秀的程序员,十分优秀!