顶级分析内存泄漏



大多数程序员在发现自己的程序正在泄漏内存时会做什么? 没什么,让用户购买更多的RAM。我敢于假设他们采用了经过时间考验的可靠工具,例如valgrind或libasan,可以运行并观看报告。通常说,在这样的文件的程序行中创建的对象没有被释放。又为什么呢 这不是写在任何地方。



这篇文章重点介绍了无用的泄漏查找器,基本的统计分析概念以及如何应用它。



我已经写过关于哈勃尔神魂颠倒的文章,但我仍将在总体上重复主要思想。如果某些对象未释放,则它们将累积在内存中。这意味着我们有许多同类的,相似的序列。如果泄漏量超过实际使用量,则其中最常见的是泄漏物体的一部分。通常,C ++程序包含指向vtbl类的指针。这样我们可以找出忘记释放的对象的类型。显然,顶部包含大量垃圾,经常遇到的行,并且相同的valgrind会告诉我们什么以及在哪里流动更好。但是topleaked最初并不是为了与多年来制定的技术竞争而创建的。它被认为是解决其他问题无法解决的问题的工具-无法再现的泄漏分析。如果在测试环境中无法重现该问题,那么任何动态分析都是没有用的。如果错误仅在“战斗中”发生,甚至不稳定,那么我们可以获得的最大值是日志和内存转储。可以分析此转储。



C++ , - abort()



#include <iostream>
#include <assert.h>
#include <unistd.h>

class A {
    size_t val = 12345678910;
    virtual ~A(){}
};

int main() {
    for (size_t i =0; i < 1000000; i++) {
        new A();
    }
    std::cout << getpid() << std::endl;
    abort();
}


topleaked



./toleaked leak.core


— .



0x0000000000000000 : 1050347
0x0000000000000021 : 1000003
0x00000002dfdc1c3e : 1000000
0x0000558087922d90 : 1000000
0x0000000000000002 : 198
0x0000000000000001 : 180
0x00007f4247c6a000 : 164
0x0000000000000008 : 160
0x00007f4247c5c438 : 153
0xffffffffffffffff : 141


, 0x2dfdc1c3e, 12345678910, . , . , , gdb gdb . -ogdb — , gdb.



$ ./topleaked -n10 -ogdb /home/core/leak.1002.core | gdb leak /home/core/leak.1002.core
...<   gdb  >
#0  0x00007f424784e6f4 in __GI___nanosleep (requested_time=requested_time@entry=0x7ffcfffedb50, remaining=remaining@entry=0x7ffcfffedb50) at ../sysdeps/unix/sysv/linux/nanosleep.c:28
28      ../sysdeps/unix/sysv/linux/nanosleep.c: No such file or directory.
(gdb) $1 = 1050347
(gdb) 0x0:      Cannot access memory at address 0x0
(gdb) No symbol matches 0x0000000000000000.
(gdb) $2 = 1000003
(gdb) 0x21:     Cannot access memory at address 0x21
(gdb) No symbol matches 0x0000000000000021.
(gdb) $3 = 1000000
(gdb) 0x2dfdc1c3e:      Cannot access memory at address 0x2dfdc1c3e
(gdb) No symbol matches 0x00000002dfdc1c3e.
(gdb) $4 = 1000000
(gdb) 0x558087922d90 <_ZTV1A+16>:       0x87721bfa
(gdb) vtable for A + 16 in section .data.rel.ro of /home/g.smorkalov/dlang/topleaked/leak
(gdb) $5 = 198
(gdb) 0x2:      Cannot access memory at address 0x2
(gdb) No symbol matches 0x0000000000000002.
(gdb) $6 = 180
(gdb) 0x1:      Cannot access memory at address 0x1
(gdb) No symbol matches 0x0000000000000001.
(gdb) $7 = 164
(gdb) 0x7f4247c6a000:   0x47ae6000
(gdb) No symbol matches 0x00007f4247c6a000.
(gdb) $8 = 160
(gdb) 0x8:      Cannot access memory at address 0x8
(gdb) No symbol matches 0x0000000000000008.
(gdb) $9 = 153
(gdb) 0x7f4247c5c438 <_ZTVN10__cxxabiv120__si_class_type_infoE+16>:     0x47b79660
(gdb) vtable for __cxxabiv1::__si_class_type_info + 16 in section .data.rel.ro of /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) $10 = 141
(gdb) 0xffffffffffffffff:       Cannot access memory at address 0xffffffffffffffff
(gdb) No symbol matches 0xffffffffffffffff.
(gdb) quit


, . $4 = 1000000 . x info symbol . , vtable for A, A.



. , , 15. , .



, ?



— ? , , . topleaked . , , , . ? , , . , , .





. , . — . 3 . , . 3 , - . , 2-3 — . . , — , . C++ . , . C, D, Rust, Go NodeJS. , js .



. , , , , close. , . ( ), , fd (512000 ) . . . , , .





topleaked — . , , . , , . : . state — enum, . : , , websocket, . , , .



. Topleaked , , 8 8- . - , , , - . - , . , vtbl, . , , “ ”. vtbl - state. , . .



C++ — ABI - . POD trivial C. , , . . , linux gcc , vtbl — . offsetof(state) . :



struct Base {
    virtual void foo() = 0;
};

struct Der : Base {
    size_t a = 15;
    void foo() override {

    }
};
int main()
{
    for (size_t i = 0; i < 10000; ++i) {
        new Der;
    }
    auto d = new Der;
    cout << offsetof(Der, a) << endl;
    abort();
    return 0;
}


offsetof Der::a, “” 10000 . topleaked



topleaked  my_core.core
0x0000000000000000 : 50124
0x000000000000000f : 10005
0x0000000000000021 : 10004
0x000055697c45cd78 : 10002
0x0000000000000002 : 195
0x0000000000000001 : 182
0x00007fe9cbd6c000 : 167
0x0000000000000008 : 161
0x00007fe9cbd5e438 : 154
0x0000000000001000 : 112


0x000055697c45cd78 vtbl Der. offsetof 8. , 8 . topleaked — . -f , , --memberOffset — -f, --memberType — . uint8, uint16, uint32 uint64.



topleaked my_core.core -f0x55697c45cd78 --memberOffset=8 --memberType=uint64


:



0x000000000000000f : 10001
0x000055697ccaa080 : 1


10000 0x0f, , .



Happy End



. , , , . , . , . , , . , TCP, — websocket upgrade, - . . — , . , (, ) TCP. , , . . , , — TCP Keep Alive. https://blog.cloudflare.com/when-tcp-sockets-refuse-to-die/



, . , . websocket . , .



D



, . , , (uint 8/16/32/64) :



readFile(name, offset, limit)
    .findMember!uint64_t(pattern, memberOffset)
    .findMostFrequent(size).printResult(format);


findMember — , , findMostFrequent — , . (ranges) . , , , .



, . D. : dmd — , ldc — llvm gdc, gcc, 9- . , , , gcc. , ldc, . .



dub. topleaked :



dub fetch topleaked


:



dub run topleaked -brelease-nobounds -- <filename> [<options>...]


dub run brelease-nobounds :



dub build -brelease-nobounds


topleaked.



c



P.S. Crazy Panda , . , topleaked.




All Articles