【问题标题】:Implementing reference counts with C++使用 C++ 实现引用计数
【发布时间】:2013-11-17 05:29:32
【问题描述】:

我正在研究我的数字信号处理框架。为了提供数据交换接口,我将所有缓冲区包装在一个 Data 类中,该类具有基于引用计数的 GC 机制(系统很简单,所以我相信 ref count 可以处理这个问题)。

它是这样工作的:

  1. 在构造 Data 实例时,它会将其引用计数设置为零。
  2. 当实例被分派到 N 个 DSP 模块时,将 N 添加到它的引用计数中。
  3. 当 DSP 模块完成实例时,它会减少引用计数。
  4. 当引用计数减少到零时,它删除它;

但是我发现我的程序中存在内存泄漏。

为了调试,我在Data类中添加了静态变量m_alloccount和m_freecount来记录分配和释放的时间。然后我随机暂停执行,才发现这两个数字之间只有细微的差别。

例如在不同的试验中:

Trial         1   2    3      4
m_alloccount  12  924  34413  364427
m_freecount   11  923  34412  364425

但事实是内存使用量仍在增长。我相信所有内存分配都绑定到 Data 类。现在实在想不通原因。

int Data::m_alloctime=0;
int Data::m_freetime=0;

Data::Data(DataPinOut*parent, int type, int size)
:m_ptr(NULL)
,m_parent(parent)
,m_refcnt(0)
,m_type(type)
,m_size(size)
{
    if(size>0)
        m_ptr=new char[TypeSizeLookup()*size];
    m_alloctime++;
}

Data::~Data()
{
    delete [] (char*)m_ptr;
    m_freetime++;
}

void Data::Delete()
{
    std::lock_guard<std::mutex>*lock=new std::lock_guard<std::mutex>(m_mutex);

    if(m_refcnt>1)
    {
        m_refcnt--;
        delete lock;
    }
    else
    {
        delete lock;
        delete this;
    }
}

【问题讨论】:

  • 你用过valgrind吗?
  • 这是多线程的吗?
  • 交出std::shared_ptr,不用担心自己的数量。
  • 你看过std::shared_ptr,C++11 中的标准引用计数工具吗?
  • @babel92 你能告诉我们你是如何确定内存泄漏的吗?谢谢

标签: c++ memory-leaks reference-counting


【解决方案1】:

根据我的经验,无论内部操作的数量如何,只有一两次的内存泄漏表明输入或输出变量存在泄漏。检查系统外部接口的记账一致性。

std::shared_ptr 很好,因为它是标准的,它自动适合作为外部接口。用户可以在不知道DSP定义的管理细节的情况下与引用计数的对象进行交互。

除此之外,我们无法通过直觉了解您的程序中发生了什么。

【讨论】:

  • 如果他在随机时间暂停,这些数字并没有多大意义——差异可能只是当时的活动对象。我更怀疑他是如何确定这是内存泄漏,因为它可能是碎片而不导致内存交还等
  • @imsoconfused 我假设他发布的试验表是从输入到最终输出的完整操作。但很有可能他只是在处理最终输出对象之前打印了统计数据。这可能被视为错误,也可能不被视为错误。
  • 不——他在问题“然后我随机暂停执行,只发现两个数字之间只有细微差别。”
  • @imsoconfused 是的,但这可能与试验不同。我可能是错的。
  • 哦,是的,这是另一种解释。我只是使用英特尔 VTune/Inspector 并切入主题
【解决方案2】:

您如何维护您的计数器?如果您的计数器递减/测试不是原子的,您可能会泄漏 递减,这将阻止对象达到 0 的引用计数。

【讨论】:

  • 我使用 std::lock_guard 和互斥锁来保护与引用计数操作相关的每个函数。
【解决方案3】:

第 2 步。在调度时添加 n 个引用。

模块是否保证被调度?根据您的简单算法语句,未调度的已创建模块没有任何机制可以减少和删除其引用计数。

【讨论】:

  • 是的。每个块的线程等待其所有输入引脚被加载,然后执行其工作。之后它会减少输入数据的引用计数。
  • 并且没有会导致未分派的数据实例的故障路径?
  • 不太可能,因为在我的测试示例中只有三个块... A->B->C ....
  • 回到 COM 的旧时代,在共享 ptr 等之前,引用计数泄漏的最常见原因是错误条件下不正确的 derefs,所以也许需要考虑一些事情,因为听起来你正在管理它明确地。祝你好运。
猜你喜欢
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 2011-08-28
  • 1970-01-01
  • 2016-03-14
  • 1970-01-01
相关资源
最近更新 更多