Valgrind 在使用适当的 free() 和 end() 后显示 ncurses 命令的内存泄漏

Valgrind shows memory leaks from ncurses commands after using appropriate free() and end()

我正在编写一个程序来更好地理解 ncurses,当我通过 valgrind 推送它时,它会输出许多与 ncurses 命令相关的泄漏。 但是,我只用了stdscr,在main()的最后调用了endwin()。我使用 menu.h 设置了用户选项,最后使用 free_item 和 free_menu:

menuChoice(WINDOW* scr, std::vector<std::string> *choices,
    std::string desc)
{
    //create the menu and the item pointer vector
    MENU* my_menu;
    std::vector<ITEM*> my_items;
    ITEM* cur = NULL;
    for (int x = 0; x < choices->size(); x++)
    {
        //populate the items vector with the string data in choices
        my_items.push_back(new_item(choices->at(x).c_str(), NULL));
    }
    //pushback a null item
    my_items.push_back((ITEM*)NULL);
    //create the menu and attach the items
    my_menu = new_menu((ITEM**)my_items.data());
    //print the desc and post the menu
    mvwprintw(scr, LINES - 3, 0, "%s\n", desc.c_str());
    post_menu(my_menu);
    wrefresh(scr);
    int c = 0;
    while((c = wgetch(scr)) != '\n')
    {   switch(c)
        {   case KEY_DOWN:
                menu_driver(my_menu, REQ_DOWN_ITEM);
                break;
            case KEY_UP:
                menu_driver(my_menu, REQ_UP_ITEM);
                break;
        }
    }
    cur = current_item(my_menu);
    int toReturn;
    toReturn = boost::lexical_cast<int>((char*) item_name(cur));
    unpost_menu(my_menu);
    for (int x = 0; x < my_items.size(); x++)
    {
        free_item(my_items[x]);
    }
    free_menu(my_menu);
    return toReturn;
}

然而,valgrind 仍然给了我很多这样的东西:

==25266==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25266==    by 0x405F2F3: _nc_hash_map (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x405E606: _nc_scroll_optimize (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x4075FF1: doupdate (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x406B02E: wrefresh (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x4064AAF: ??? (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x4064C46: _nc_wgetch (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x40658B9: wgetch (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x804B309: blackjack::menuChoice(_win_st*, std::vector<std::string, std::allocator<std::string> >*, std::string) (blackjack.cpp:555)
==25266==    by 0x804AF66: blackjack::prefScreen(_win_st*) (blackjack.cpp:521)
==25266==    by 0x8049BFF: blackjack::blackjack(_win_st*) (blackjack.cpp:21)
==25266==    by 0x8050118: blackjack_routine(_win_st*) (main.cpp:50)
==25266== 
==25266== 1,900 bytes in 1 blocks are still reachable in loss record 44 of 49
==25266==    at 0x402C324: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25266==    by 0x4088068: _nc_doalloc (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x4090076: _nc_read_termtype (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x40903EB: _nc_read_file_entry (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x4090578: _nc_read_entry (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x408A5E4: _nc_setup_tinfo (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x408A95B: _nc_setupterm (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x4069580: newterm (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x4066013: initscr (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x80500C2: main (main.cpp:36)
==25266== 
==25266== 2,836 bytes in 1 blocks are still reachable in loss record 45 of 49
==25266==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25266==    by 0x408807F: _nc_doalloc (in /lib/i386-linux-gnu/libtinfo.so.5.9)
==25266==    by 0x406F026: _nc_printf_string (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x406AB22: vwprintw (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x406AC68: mvwprintw (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x804B2A3: blackjack::menuChoice(_win_st*, std::vector<std::string, std::allocator<std::string> >*, std::string) (blackjack.cpp:550)
==25266==    by 0x804AF66: blackjack::prefScreen(_win_st*) (blackjack.cpp:521)
==25266==    by 0x8049BFF: blackjack::blackjack(_win_st*) (blackjack.cpp:21)
==25266==    by 0x8050118: blackjack_routine(_win_st*) (main.cpp:50)
==25266==    by 0x80500F3: main (main.cpp:41)
==25266== 
==25266== 3,182 bytes in 1 blocks are still reachable in loss record 46 of 49
==25266==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25266==    by 0x406C0CF: _nc_setupscreen (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x40695CE: newterm (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x4066013: initscr (in /lib/i386-linux-gnu/libncurses.so.5.9)
==25266==    by 0x80500C2: main (main.cpp:36)

虽然没有表现出太多的漏洞,但当我觉得自己遵守规则时,它仍然让我觉得我做错了什么。

ncurses FAQ 中对此进行了讨论 Testing for Memory Leaks:

Perhaps you used a tool such as dmalloc or valgrind to check for memory leaks. It will normally report a lot of memory still in use. That is normal.

The ncurses configure script has an option, --disable-leaks, which you can use to continue the analysis. It tells ncurses to free memory if possible. However, most of the in-use memory is "permanent".

Any implementation of curses must not free the memory associated with a screen, since (even after calling endwin()), it must be available for use in the next call to refresh(). There are also chunks of memory held for performance reasons. That makes it hard to analyze curses applications for memory leaks. To work around this, build a debugging version of the ncurses library which frees those chunks which it can, and provides the _nc_free_and_exit() function to free the remainder on exit. The ncurses utility and test programs use this feature, e.g., via the ExitProgram() macro.