|
|
(17 intermediate revisions by 3 users not shown) |
Line 1: |
Line 1: |
| <noinclude>{{documentation/versioncheck}}</noinclude> | | <noinclude>{{documentation/versioncheck}}</noinclude> |
− | Here are some tips to narrow down various issues such as crash, or memory leaks
| |
| | | |
− | =Disable features=
| + | {{documentation/banner |
− | Try running Slicer with as few features as possible:
| + | | text = [https://slicer.readthedocs.io/en/latest/user_guide/get_help.html#slicer-application-does-not-start This page has been moved to read-the-docs.] |
− | * Disable Slicer options via the command line
| + | | background-color = 8FBC8F }} |
− | *: <pre>$ ./Slicer --no-splash --ignore-slicerrc --disable-cli-module --disable-loadable-module --disable-scriptedmodule</pre>
| |
− | ** Look at all the possible options
| |
− | **: <pre>$ ./Slicer --help</pre>
| |
− | * Disable ITK plugins
| |
− | *: CLI modules silently load the ITK plugins in lib/Slicer-{{documentation/currentversion}}/ITKFactories. These plugins are used to share the volumes between Slicer and the ITK filter without having to copy them on disk.
| |
− | ** rename lib/Slicer-{{documentation/currentversion}}/ITKFactories into lib/Slicer-{{documentation/currentversion}}/ITKFactories-disabled
| |
− | * Disable Qt plugins
| |
− | ** rename lib/Slicer-{{documentation/currentversion}}/iconengine into lib/Slicer-{{documentation/currentversion}}/iconengine-disabled
| |
− | | |
− | =Track memory leaks=
| |
− | <ol>
| |
− | <li> Turn ON the VTK_DEBUG_LEAKS CMake variable and build Slicer</li>
| |
− | <li> Create a test that reproduces the memory leak systematically </li>
| |
− | After execution, the memory leaks are printed automatically by VTK on the standard output:
| |
− | 224: vtkDebugLeaks has detected LEAKS!
| |
− | 224: Class "vtkProperty2D" has 60 instances still around.
| |
− | ... | |
− | <li>Find what specific instance of a class (here vtkProperty2D) leaks.</li>
| |
− | If the class is instantiated a large amount of time, it is hard to know what instance is leaking.
| |
− | You can edit the constructor and destructor of the class (here vtkProperty2D::vtkProperty2D() and vtkProperty2D::~vtkProperty2D())
| |
− | vtkProperty2D::vtkProperty2D()
| |
− | {
| |
− | ...
| |
− | static int count = 0;
| |
− | std::cout << "CREATE vtkProperty2D instance #" << count++ << " " << this << std::endl;
| |
− | }
| |
− |
| |
− | vtkProperty2D::~vtkProperty2D()
| |
− | {
| |
− | ...
| |
− | static int count = 0;
| |
− | std::cout << "DELETE vtkProperty2D instance #" << count++ << " " << this << std::endl;
| |
− | }
| |
− | Don't forget to rebuild VTK if the class is from VTK (and not just Slicer inner build)
| |
− | After running the test again, you should see a list of
| |
− | ...
| |
− | CREATE vtkProperty2D instance #0 0x0123456
| |
− | ...
| |
− | CREATE vtkProperty2D instance #1 0x01234E5
| |
− | ...
| |
− | DELETE vtkProperty2D instance #0 0x0123456
| |
− | ...
| |
− | DELETE vtkProperty2D instance #1 0x01234E5
| |
− | ...
| |
− | CREATE vtkProperty2D instance #2 0x0123A23
| |
− | ...
| |
− | CREATE vtkProperty2D instance #3 0x0124312
| |
− | ...
| |
− | Copy/paste the listing in a text editor and ensure that for each CREATE of a pointer (e.g. 0x0123456) it exists a DELETE. If there isn't, you found what instance is leaking. Note the instance # (here instance #2 and #3)
| |
− | Run the test with the [[Documentation/4.0/Developers/Tutorials/Debug_Instructions|debugger]], set a breakpoint in the class constructor and ignore the break as many time as the instance number:
| |
− | (gdb) break vtkProperty2D::vtkProperty2D()
| |
− | Breakpoint 1 at 0x5b22d0e55d04296: file vtkProperty2D.cxx, line 22
| |
− | (gdb) ignore 1 2
| |
− | When the debugger stops, check the call stack:
| |
− | (gdb) backtrace
| |
− | By analyzing the trace, you should be able to find the faulty instance.
| |
− | </li>
| |
− | <li> Analyze the code to see where the leak could be</li>
| |
− | Here is a listing of the most common mistakes
| |
− | * this->MyXXX = vtkXXX::New();
| |
− | ** Is there a matching this->MyXXX->Delete() ?
| |
− | ** Are you sure <code>this->MyXXX</code> is <code>0</code> before being assigned a new pointer ? If not, then you need to add
| |
− | if (this->MyXXX != 0)
| |
− | {
| |
− | this->MyXXX->Delete();
| |
− | this->MyXXX = 0;
| |
− | }
| |
− | this->MyXXX = vtkXXX::New();
| |
− | </ol>
| |
− | {{ombox
| |
− | |type=content
| |
− | |text=To reduce memory leaks, use the following tools:
| |
− | * <code>vtkNew<vtkXXX> myXXX;</code>
| |
− | * <code>vtkSmartPointer<vtkXXX> myXXX = vtkSmartPointer<vtkXXX>::New()</code>
| |
− | * <code>vtkSmartPointer<vtkXXX> myXXX; myXXX.TakeReference(this->CreateObjAndCallerOwnsReference())</code>.
| |
− | }}
| |
− | | |
− | =Track a crash while accessing already deleted object pointer=
| |
− | If the application crashes by accessing an invalid pointer. The goal here is to find when (and why) the pointer is deleted before it is accessed .
| |
− | <ol>
| |
− | <li>Before the crash, print the value of the pointer:</li>
| |
− | Add before the crash (i.e. <code>this->MyObject->update()</code>)
| |
− | std::cout << ">>>>>Object pointer: " << this->MyObject << std::endl;
| |
− | <li>Add a counter in the destructor:</li>
| |
− | Add in the object destructor (it can be in the base class (vtkObject or vtkMRMLNode) if you don't know the type):
| |
− | static int count = 0;
| |
− | std::cout << "#######Object Destructed: " << this << " " << count++ << std::endl;
| |
− | <li>Run the application and make it crash.</li>
| |
− | <li>In the logs you shall see something like that:</li>
| |
− | #######Object Destructed: 0x12345678 0
| |
− | #######Object Destructed: 0x12345679 1
| |
− | #######Object Destructed: 0x12345680 2
| |
− | >>>>>Object Pointer: 0x12345660
| |
− | >>>>>Object Pointer: 0x12345661
| |
− | >>>>>Object Pointer: 0x12345662
| |
− | #######Object Destructed: 0x12345660 3
| |
− | #######Object Destructed: 0x12345661 4
| |
− | #######Object Destructed: 0x12345662 5
| |
− | #######Object Destructed: 0x12345663 6
| |
− | >>>>>Object Pointer: 0x12345670
| |
− | >>>>>Object Pointer: 0x12345671
| |
− | >>>>>Object Pointer: 0x12345672
| |
− | #######Object Destructed: 0x12345660 7
| |
− | #######Object Destructed: 0x12345661 8
| |
− | #######Object Destructed: 0x12345662 9
| |
− | >>>>>Object Pointer: '''0x12345663'''
| |
− | Segfault
| |
− | <li> Search in the logs when the pointer before crash has been deleted. Set a conditional breakpoint in the debugger:</li>
| |
− | (gdb) break MyObj.cxx:103 if count == 6
| |
− | or
| |
− | (gdb) break MyObj.cxx:103
| |
− | (gdb) ignore 1 5
| |
− | or if you don't want to use a debugger, you can make it crash the 6th time:
| |
− | assert(count != 6);
| |
− | <li> Analyze the backtrace to understand why the pointer has been deleted without letting know the object that tries to access it.</li>
| |
− | </ol>
| |
− | | |
− | =Console output on Windows=
| |
− | On Windows, the application is built with no console output. A workaround for this issue is described in the following bug reports:
| |
− | * http://www.na-mic.org/Bug/view.php?id=2376
| |
− | * http://www.na-mic.org/Bug/view.php?id=2917
| |
− | To add console output, you need to compile Slicer application with Slicer_BUILD_WIN32_CONSOLE set to ON at the configure time (uninitialized/OFF by default).
| |