|
|
(9 intermediate revisions by the same user 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.
| |
− | ...
| |
− | Alternatively, you can simply run Slicer instead of a custom test.
| |
− | | |
− | <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. By making verbose the constructor and destructor of the faulty class, you can infer which instance is leaking. Below are 2 techniques to print whenever the con/destructors are called:
| |
− | <ol>
| |
− | <li>By recompiling VTK</li>
| |
− | 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 (no need to build Slicer inner build)
| |
− | After running the test, you should see outputs similar to
| |
− | ...
| |
− | 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)
| |
− | | |
− | <li>Without recompiling any library but using the debugger</li>
| |
− | Any debugger with advanced breakpoint controls should work.
| |
− | * With Visual Studio
| |
− | <ol>
| |
− | <li>Set breakpoints in the class constructor and destructor methods.</li>
| |
− | <li>Right click on the breakpoint, select "When Hit..." and "Print a message" with "Function: $FUNCTION {this}". Make sure the "Continue execution" checkbox is selected.
| |
− | <li>Execute the test or Slicer</li>
| |
− | <li>Open the "Output" tab and copy paste the contents into an advanced file editor (not Visual Studio)</li>
| |
− | </ol>
| |
− | * With GDB
| |
− | <ol>
| |
− | <li>Start gdb</li>
| |
− | Using the launcher
| |
− | $ ./Slicer --gdb
| |
− | Or sometimes the following works as well
| |
− | $ gdb ./bin/SlicerApp-real
| |
− | <li>Place breakpoints in the functions</li>
| |
− | (gdb) break vtkProperty2D::vtkProperty2D()
| |
− | (gdb) break vtkProperty2D::~vtkProperty2D()
| |
− | gdb will stop in those methods each time the program steps into. It will then print a line such as:
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x123456789) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22 | |
− | 22 vtkProperty2D::vtkProperty2D()
| |
− | <li>Automatically continue execution after each break</li>
| |
− | (gdb) commands 1
| |
− | > continue
| |
− | > end
| |
− | (gdb) commands 2
| |
− | > continue
| |
− | > end
| |
− | <li> Start the execution and copy paste the logs printed by gdb into an advanced file editor (e.g. emacs)</li>
| |
− | (gdb) run
| |
− | </ol>
| |
− | | |
− | After running the test(by recompiling or with debugger), you should see outputs similar to
| |
− | ...
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | 22 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | 22 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | 37 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | 37 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | 22 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0124312) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | 22 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | 37 vtkProperty2D::vtkProperty2D()
| |
− | ...
| |
− | | |
− | In an text editor, cleanup the logs by keeping only the "Breakpoint*" lines:
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0124312) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 2, vtkProperty2D::~vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:37
| |
− | | |
− | Save a copy of this file, and make the destructor lines similar to the constructor ones (using Replace tools):
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0124312) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | | |
− | Sort the file to make the constructor and destructor lines next to each other(emacs: M-x sort-lines, Notepad++: TextFX/TextFX Tools/Sort lines case sensitive):
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0124312) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | | |
− | Find the line that is not duplicated:
| |
− | * Using Notepad++ (version >=6):
| |
− | ** Open the search dialog
| |
− | ** Find what: "^(.*?)$\s+?^(?=.*^\1$)", Replace with: "dup ", toggle "Regular expression"
| |
− | ** Replace All
| |
− | ** The line without the "dup" prefix is the line we are looking for
| |
− | * Using emacs:
| |
− | ** C-M-%
| |
− | ** Replace regexp: \(.*\)<type C-q C-j>\1
| |
− | ** with: dup<type C-q C-j>
| |
− | | |
− | Extract the instance address from the line: e.g. 0x0124312
| |
− | | |
− | From the original logs, keep only the Constructor lines:
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123456) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x01234E5) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0123A23) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− | Breakpoint 1, vtkProperty2D::vtkProperty2() (this=0x0124312) at /home/user/Slicer-superbuild/VTK/.../vtkProperty2D.cxx:22
| |
− |
| |
− | Search into the original saved file what line the address is: e.g. 4
| |
− | | |
− | </ol>
| |
− | | |
− | <li>Find the leaking instance at run-time</li>
| |
− | 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 (say it's 2):
| |
− | * GDB
| |
− | (gdb) break vtkProperty2D::vtkProperty2D()
| |
− | Breakpoint 1 at 0x5b22d0e55d04296: file vtkProperty2D.cxx, line 22
| |
− | (gdb) ignore 1 2
| |
− | (gdb) run
| |
− | When the debugger stops, check the call stack:
| |
− | (gdb) backtrace
| |
− | *Visual Studio
| |
− | **Set a breakpoint in vtkProperty2D::vtkProperty2D()
| |
− | **Right click on the breakpoint and select HitCount, select "break when the hit count is equal to" and type '2'
| |
− | **Start the application
| |
− | By analyzing the trace, you should be able to find the faulty instance.
| |
− | | |
− | <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>.
| |
− | }}
| |
− | | |
− | ==Other resources==
| |
− | * [[Slicer3:VTK_Leak_Debugging|Slicer3 VTK leak debugging]]
| |
− | * [[Strategies_for_Writing_and_Debugging_Code_in_Slicer_3|Strategies for Writing and Debugging Code in Slicer3]]
| |
− | | |
− | =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>
| |
− | | |
− | = Why is my VTK actor/widget not visible ?=
| |
− | * Add a breakpoint in RenderOpaqueGeometry() check if it is called. If not, then:
| |
− | ** Check its vtkProp::Visibility value.
| |
− | *** For vtkWidgets, it is the visibility of the representation.
| |
− | ** Check its GetBounds() method. If they are outside the camera frustrum, the object won't be rendered.
| |
− | *** For vtkWidgets, it is the bounds of the representation.
| |
− | | |
− | | |
− | =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).
| |
− | | |
− | =Debugging Slicer application startup isses=
| |
− | == Instruction for Windows ==
| |
− | * Your Slicer settings might have become corrupted
| |
− | ** Go to c:\Users\<yourusername>\AppData\Roaming\ directory. Rename NA-MIC to NA-MIC-backup. If you cannot find a NA-MIC directory there then check the [[Documentation/{{documentation/version}}/SlicerApplication/Settings]] page for instructions for getting the settings directory. Try to launch Slicer.
| |
− | * There may be conflicting DLLs in your system path (caused by installing applications that place libraries in incorrect location on your system)
| |
− | ** Start Event Viewer (eventvwr.exe), select Windows Logs / Application, and find the application error. If there is a DLL loading problem a line similar to this will appear: Faulting module path: <something>.dll
| |
− | ** If you found a line similar to this, then try the following workaround: Start a command window. Enter “set path=” to clear the path variable. Enter Slicer.exe to start Slicer.
| |
− | ** If Slicer starts successfully then you need to remove remove unnecessary items from the system path (or delete the libraries installed at incorrect locations).
| |
− | ** If Slicer does not work then collect some more information and report the error:
| |
− | *** Enable process loading logging using the sxstrace tool and see if it shows any errors (see instructions here: https://technet.microsoft.com/en-ca/library/hh875651.aspx).
| |
− | *** Get DLL dependency information:
| |
− | **** Download depends.exe (http://www.dependencywalker.com/)
| |
− | **** Run depends.exe using the Slicer launcher: Slicer.exe --launch .............\depends.exe "bin\SlicerApp-real.exe"
| |
− | **** In dependency walker:
| |
− | ***** Make sure the full path of DLLs are shown (click View / Full paths if you only see the DLL names)
| |
− | ***** File / Save as... => Comma Separated Values (*.csv)
| |