gpt4 book ai didi

c++ - 查找 shared_ptr 的引用计数增加的位置

转载 作者:太空狗 更新时间:2023-10-29 21:19:09 29 4
gpt4 key购买 nike

我有一些代码存在内存泄漏,因为它在其 shared_ptr 实例之间获取循环引用(这是两个 shared_ptr 实例指向的对象,每个对象都有一个内部shared_ptr 对另一个类实例的引用。这意味着两个类都不会被销毁,因为每个类实例仍在被另一个类实例使用,从而导致内存泄漏。在某些情况下,它是单个 shared_ptr 也引用自身的类的实例。)

通过 Valgrind 运行代码很有帮助,因为它告诉我内存最初分配的位置,但这不是循环引用的来源。我需要找到特定共享指针(Valgrind 提示的那个)的引用计数增加的所有位置,因为其中一个必须更改为 weak_ptr 才能解决问题。

我如何选择一个特定的 shared_ptr 并获取其引用计数增加的所有源代码行的列表?

我在 Linux 下运行 GCC/GDB 和 Valgrind,但欢迎使用平台中立的解决方案。

下面是一些演示问题的示例代码:

#include <boost/shared_ptr.hpp>

struct Base {
int i;
};
struct A: public Base {
int a;
boost::shared_ptr<Base> ptrInA;
};
struct B: public Base {
int b;
boost::shared_ptr<Base> ptrInB;
};

int main(void)
{
boost::shared_ptr<A> a(new A); // Line 17
boost::shared_ptr<B> b(new B);
a->ptrInA = b; // Line 19
b->ptrInB = a;
return 0;
}

在 Valgrind 下运行时,它说:

HEAP SUMMARY:
in use at exit: 96 bytes in 4 blocks
total heap usage: 4 allocs, 0 frees, 96 bytes allocated

96 (24 direct, 72 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
at 0x4C2A4F0: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x40099A: main (test.cpp:17)

LEAK SUMMARY:
definitely lost: 24 bytes in 1 blocks
indirectly lost: 72 bytes in 3 blocks

我正在寻找一种解决方案,它会指出源文件中的第 19-20 行是循环的可能原因,这样我就可以检查代码并决定是否需要更改它。

最佳答案

基于@dandan78 的方法。这是一个更详细的例子GDB CLI,它在 shared_ptr 的引用计数更改上创建断点。

主要.cpp:

#include <iostream>
#include <memory>

using namespace std;

#define DBG(msg) std::cout << msg << std::endl;

class A {
public:
A(int i) {
mI = i;
DBG("A() this:"<<this<<" i:"<<mI);
}
~A() {
DBG("~A() this:"<<this<<" i:"<<mI);
}
private:
int mI = 0;
};

int main() {
std::shared_ptr<A> p1(new A(0x12345678));
DBG("p1 use_count:"<<p1.use_count());
{
auto p2 = p1;
DBG("p1 use_count:"<<p1.use_count());
DBG("p2 use_count:"<<p2.use_count());
auto p3 = p1;
DBG("p1 use_count:"<<p1.use_count());
DBG("p2 use_count:"<<p2.use_count());
DBG("p3 use_count:"<<p3.use_count());
}
DBG("p1 use_count:"<<p1.use_count());
return 0;
}

生成文件:

CXXFLAGS = -O0 -ggdb

main: main.cpp
$(CXX) $(CXXFLAGS) -o $@ $<

程序的输出:

A() this:0x6c6fb0 i:305419896
p1 use_count:1
p1 use_count:2
p2 use_count:2
p1 use_count:3
p2 use_count:3
p3 use_count:3
p1 use_count:1
~A() this:0x6c6fb0 i:305419896

编译并运行gdb(不要把#注释粘贴到gdb):

make
gdb main 2>&1 | tee out.log

GDB session :

(gdb) b main.cpp:23   # right after the p1 initialization
(gdb) r
Thread 1 hit Breakpoint 1, main () at main.cpp:23
(gdb) x/2xg &p1
0x62fe00: 0x0000000000fd4a10 0x0000000000fd4a50
# First pointer points to the target A object, sencond points to the reference counter
# Inspect the refcount data:
(gdb) x/4xw 0x0000000000fd4a50
0xfd4a50: 0x00405670 0x00000000 0x00000003 0x00000001
# The third integer is use_count of the shared_ptr, which can be printed by:
(gdb) x/1xw 0x0000000000fd4a50 + 8
0xfd4a58: 0x00000001

# Add a watchpoint for the use_count address
(gdb) watch *(int*)(0x0000000000fd4a50 + 8)
Hardware watchpoint 2: *(int*)(0x0000000000fd4a50 + 8)
# Add commands for the new watchpoint 2:
(gdb) commands 2
bt # backtrace
c # continue
end # end of the handler script

(gdb) c # Continue the program

现在您可以检查 out.log 文件并分析 use_count 发生变化的所有回溯。

也可以直接添加 gdb 观察点:

watch *(*((int**)(&p1) + 1) + 2)
^--------------- the shared_ptr variable
^--------- +1 pointer to the right (+8 bytes in 64bit programm)
^---- +2 integers to the right (+8 bytes)

如果您使用优化进行编译,shared_ptr 变量可能已经被优化掉了。只需在您的代码中直接打印它,然后获取 shared_ptr 对象的地址并将其粘贴到您的 gdb session 中:

std::cout << "p1:" << (void*)&p1 << std::endl;

关于c++ - 查找 shared_ptr 的引用计数增加的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28291515/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com