简体   繁体   中英

Do I have to delete pointers to widgets in FLTK?

So I have the following code:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    wptr->show();
    Fl::run();
    return 0;
}
> valgrind --leak-check=full -s ./run
==13685== Memcheck, a memory error detector
==13685== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13685== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==13685== Command: ./run
==13685==
==13685==
==13685== HEAP SUMMARY:
==13685==     in use at exit: 741,252 bytes in 1,107 blocks
==13685==   total heap usage: 14,853 allocs, 13,746 frees, 2,829,612 bytes allocated
==13685==
==13685== LEAK SUMMARY:
==13685==    definitely lost: 0 bytes in 0 blocks
==13685==    indirectly lost: 0 bytes in 0 blocks
==13685==      possibly lost: 0 bytes in 0 blocks
==13685==    still reachable: 741,252 bytes in 1,107 blocks
==13685==         suppressed: 0 bytes in 0 blocks
==13685== Reachable blocks (those to which a pointer was found) are not shown.
==13685== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==13685==
==13685== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
--13685--
--13685-- used_suppression:      1 X on SUSE11 writev uninit padding /usr/lib/valgrind/default.supp:377
==13685==
==13685== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

Notice I did NOT delete the pointer to the window and valgrind has not detected any leaks.
I have searched the docs ( https://www.fltk.org/doc-1.3/basics.html ), as well as the FAQ pages ( https://www.fltk.org/doc-1.3/FAQ.html , https://www.fltk.org/articles.php ), and I've found that the most recent grouping widget automatically attaches newly created widgets, but I've found nothing about how memory is managed by fltk, as in, whether there is some "garbage collector", or if I have to delete the pointer manually.
Normally this output would imply that there is some hidden mechanism that is responsible for freeing memory as I have not manually freed the memory allocated for the window and there seems to be no leak, but take a look at the following modification to the previous code:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    auto box = new Fl_Box{0,0,100,100,"Hello!"}; // Adding widget
    wptr->show();
    Fl::run();
    return 0;
}
valgrind --leak-check=full -s ./run
==14005== Memcheck, a memory error detector
==14005== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14005== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==14005== Command: ./run
==14005==
==14005==
==14005== HEAP SUMMARY:
==14005==     in use at exit: 1,101,954 bytes in 11,185 blocks
==14005==   total heap usage: 31,631 allocs, 20,446 frees, 7,013,742 bytes allocated
==14005==
==14005== 384 (256 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 368 of 540
==14005==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14005==    by 0x4EC8255: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ECC200: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4D433BF: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D438F5: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D43C96: ??? (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D44080: XftDefaultHasRender (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D44558: XftDefaultSubstitute (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4D46FD3: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14005==
==14005== 2,565 (768 direct, 1,797 indirect) bytes in 1 blocks are definitely lost in loss record 482 of 540
==14005==    at 0x484383F: realloc (vg_replace_malloc.c:1192)
==14005==    by 0x4EC830E: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED94DA: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED156C: FcFontRenderPrepare (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4ED1B9D: FcFontMatch (in /usr/lib/libfontconfig.so.1.12.0)
==14005==    by 0x4D46FEF: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14005==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4B3390A: Fl_Widget::draw_label(int, int, int, int, unsigned int) const (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4AD8D70: Fl_Group::draw_child(Fl_Widget&) const (in /usr/lib/libfltk.so.1.3.7)
==14005==    by 0x4AD8F92: Fl_Group::draw_children() (in /usr/lib/libfltk.so.1.3.7)
==14005==
==14005== LEAK SUMMARY:
==14005==    definitely lost: 1,024 bytes in 2 blocks
==14005==    indirectly lost: 1,925 bytes in 69 blocks
==14005==      possibly lost: 0 bytes in 0 blocks
==14005==    still reachable: 1,099,005 bytes in 11,114 blocks
==14005==         suppressed: 0 bytes in 0 blocks
==14005== Reachable blocks (those to which a pointer was found) are not shown.
==14005== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==14005==
==14005== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)
--14005--
--14005-- used_suppression:      1 X on SUSE11 writev uninit padding /usr/lib/valgrind/default.supp:377
==14005==
==14005== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

Now it seems that there is a memory leak. It appears that the font library is causing this.
I will again modify the code to delete the pointers to the widgets:

int main(int, char **) {
    auto wptr = new Fl_Double_Window{640,480};
    auto box = new Fl_Box{0,0,100,100,"Hello!"};
    wptr->show();
    Fl::run();
    delete wptr;
    delete box;
    return 0;
}
> valgrind --leak-check=full ./run
==14238== Memcheck, a memory error detector
==14238== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14238== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==14238== Command: ./run
==14238==
==14238== Invalid read of size 8
==14238==    at 0x1091CA: main (main.cpp:64)
==14238==  Address 0x58a8730 is 0 bytes inside a block of size 120 free'd
==14238==    at 0x48419AB: operator delete(void*, unsigned long) (vg_replace_malloc.c:814)
==14238==    by 0x4AD862D: Fl_Group::clear() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD86E7: Fl_Group::~Fl_Group() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD1889: Fl_Double_Window::~Fl_Double_Window() (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x1091C0: main (main.cpp:63)
==14238==  Block was alloc'd at
==14238==    at 0x483EF3F: operator new(unsigned long) (vg_replace_malloc.c:417)
==14238==    by 0x10915F: main (main.cpp:60)
==14238==
==14238== Jump to the invalid address stated on the next line
==14238==    at 0x0: ???
==14238==    by 0x51D4B24: (below main) (in /usr/lib/libc-2.33.so)
==14238==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==14238==
==14238==
==14238== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==14238==  Bad permissions for mapped region at address 0x0
==14238==    at 0x0: ???
==14238==    by 0x51D4B24: (below main) (in /usr/lib/libc-2.33.so)
==14238==
==14238== HEAP SUMMARY:
==14238==     in use at exit: 1,156,045 bytes in 11,490 blocks
==14238==   total heap usage: 31,586 allocs, 20,096 frees, 7,058,062 bytes allocated
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 277 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E73EE: __glDispatchInit (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x54600AA: ??? (in /usr/lib/libGLX.so.0.0.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 278 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E75D3: __glDispatchRegisterStubCallbacks (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x538E076: ??? (in /usr/lib/libOpenGL.so.0.0.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 80 bytes in 1 blocks are possibly lost in loss record 279 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x53E6D37: ??? (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x53E75D3: __glDispatchRegisterStubCallbacks (in /usr/lib/libGLdispatch.so.0.0.0)
==14238==    by 0x4A22076: ??? (in /usr/lib/libGL.so.1.7.0)
==14238==    by 0x400FE2D: call_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x400FF1B: _dl_init (in /usr/lib/ld-2.33.so)
==14238==    by 0x40010C9: ??? (in /usr/lib/ld-2.33.so)
==14238==
==14238== 384 (256 direct, 128 indirect) bytes in 1 blocks are definitely lost in loss record 380 of 558
==14238==    at 0x483E7C5: malloc (vg_replace_malloc.c:380)
==14238==    by 0x4EC8255: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ECC200: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4D433BF: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D438F5: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D43C96: ??? (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D44080: XftDefaultHasRender (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D44558: XftDefaultSubstitute (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4D46FD3: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14238==
==14238== 2,565 (768 direct, 1,797 indirect) bytes in 1 blocks are definitely lost in loss record 498 of 558
==14238==    at 0x484383F: realloc (vg_replace_malloc.c:1192)
==14238==    by 0x4EC830E: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED94DA: ??? (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED156C: FcFontRenderPrepare (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4ED1B9D: FcFontMatch (in /usr/lib/libfontconfig.so.1.12.0)
==14238==    by 0x4D46FEF: XftFontMatch (in /usr/lib/libXft.so.2.3.4)
==14238==    by 0x4B30739: Fl_Font_Descriptor::Fl_Font_Descriptor(char const*, int, int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B309F2: ??? (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B337BB: fl_normal_label(Fl_Label const*, int, int, int, int, unsigned int) (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4B3390A: Fl_Widget::draw_label(int, int, int, int, unsigned int) const (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD8D70: Fl_Group::draw_child(Fl_Widget&) const (in /usr/lib/libfltk.so.1.3.7)
==14238==    by 0x4AD8F92: Fl_Group::draw_children() (in /usr/lib/libfltk.so.1.3.7)
==14238==
==14238== LEAK SUMMARY:
==14238==    definitely lost: 1,024 bytes in 2 blocks
==14238==    indirectly lost: 1,925 bytes in 69 blocks
==14238==      possibly lost: 240 bytes in 3 blocks
==14238==    still reachable: 1,152,856 bytes in 11,416 blocks
==14238==         suppressed: 0 bytes in 0 blocks
==14238== Reachable blocks (those to which a pointer was found) are not shown.
==14238== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==14238==
==14238== For lists of detected and suppressed errors, rerun with: -s
==14238== ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 1 from 1)
Segmentation fault (core dumped)

To say the least this modification only worsened the condition XD.
In fact, (If I'm not mistaken) the "bad permissions for mapped region..." hints that an attempt has been made to free memory twice, which would suggest that there is indeed some memory management mechanism in fltk.
But then I found this: How to fix memory leaks in simplest FLTK programm? Which implies that I should delete the pointers so right now I feel somewhat confused :)
My best guess is that:
(1) the font library is malfunctioning and
(2) FLTK has some internal garbage collector (so I shouldn't delete widget pointers manually so as not to cause any errors), can anyone confirm?

This is 2/3 of the answer. I'll have to try out FLTK on a Linux environment to work out the other 1/3.

FLTK will delete the child widgets when a window is deleted. If you look in the destructor of FL_DoubleWindow, it reads

/**
  The destructor <I>also deletes all the children</I>. This allows a
  whole tree to be deleted at once, without having to keep a pointer to
  all the children in the user code.
*/
Fl_Double_Window::~Fl_Double_Window() {
  hide();
}

I can't explain the second case but in the third case, the box is a child of the window and gets deleted when the window gets deleted. So when the code deletes box, it is deleting a deleted item, hence the error.

Valgrind logs clearly show that pointers allocated by Fl_Double_Window and new Fl_Box are not leaked, so it would not be reasonable to try and delete them manually.

The font library has a "leak"; is designed to work this way. Whether it is a good design or not is debatable, but this is the design. When it loads a font, it leaves it there until the application finishes. The application can use any font at any moment. There is no good place to free fonts, other than at application exit, and application exit clears everything up anyway. An application is unlikely to use a billion different fonts (more likely 3 to 10) so there is no risk of filling the memory with unused fonts. If your application does use a billion different fonts, you better find a way to cache them reasonably according to your application needs; a simple font library is unlikely to do a good job of it.

Exhibit A .

But have you managed to find out where the outermost widgets get deleted? In this case the Fl_Double_Window.

FLTK does not delete such outermost widgets - usually windows - by itself. Such widgets are deleted when they go out of scope (if allocated on the stack) or by using operator delete (which is the programmer's responsibility).

I just tried recompiling all three situations (with the -O0 -g ops) and running valgrind: creating an Fl_Double_Window on the stack (leak free), creating an Fl_Double_Window on the heap and not deleting it (leak free), and finally, creating an Fl_Double_Window on the heap and deleting it (leak free).

As someone else noted valgrind shows you the status right before the program exits. valgrind says among others "still reachable: 741,252 bytes in 1,107 blocks" in the OP's message and "Reachable blocks (those to which a pointer was found) are not shown" which means that in case 2 (on the heap) valgrind doesn't report a "leak" because there's still a pointer that points at the window.

Deleting the window (case 3) doesn't change much because it is done right before the program ends and it would release allocated memory anyway. The difference is only that using delete runs the destructors which means that other resources can be freed (buffered data can be written, files can be closed or deleted, etc.).

Whether something should be considered a leak depends on the behavior during runtime. If your program often allocates windows and widgets on the heap and doesn't delete them, then this constitutes a memory leak (but that's not FLTK's fault then). FLTK guarantees that all child widgets of eg a window are deleted when the parent window is deleted. That's all. There is no garbage collector running in the background.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM