OTcl, especially TclCL, provides a way to allocate new objects, however, it does not accordingly provide a garbage collection mechanism for these allocated objects. This can easily lead to unintentional memory leaks. Important: tools such as dmalloc and purify are unable to detect this kind of memory leaks. For example, consider this simple piece of OTcl script:
set ns [new Simulator] for {set i 0} {$i < 500} {incr i} { set a [new RandomVariable/Constant] }One would expect that the memory usage should stay the same after the first RandomVariable is allocated. However, because OTcl does not have garbage collection, when the second RandomVariable is allocated, the previous one is not freed and hence results in memory leak. Unfortunately, there is no easy fix for this, because garbage collection of allocated objects is essentially incompatible with the spirit of Tcl. The only way to fix this now is to always explicitly free every allocated OTcl object in your script, in the same way that you take care of malloc-ed object in C/C++.
Another source is memory leak is in C/C++. This is much easier to
track given tools that are specifically designed for this task, e.g.,
dmalloc and purify.
Ns has a special target ns-pure
to build purified ns
executable. First make sure that the macro PURIFY
in the
ns Makefile contains the right -collector
for your
linker (check purify man page if you don't know what this is).
Then simply type make ns-pure
.
See here on how to use ns with libdmalloc.
The command $ns gen-map lists all objects in a raw form.
This is useful to correlate the position and function of an object given its name. The name of the object is the OTcl handle, usually of the form ``_o###''. For TclObjects, this is also available in a C++ debugger such as gdb as this->name_.
The following macro for gdb makes it easier to see what happens in subroutines that take Tcl arguments (like TcpAgent::command()):
## for dumping Tcl-passed arguments define pargvc set $i=0 while $i < argc p argv[$i] set $i=$i+1 end end document pargvc Print out argc argv[i]'s common in Tcl code. (presumes that argc and argv are defined) end
(gdb) run Starting program: /nfs/prot/kannan/PhD/simulators/ns/ns-2/ns ... Breakpoint 1, AddressClassifier::AddressClassifier (this=0x12fbd8) at classifier-addr.cc:47 (gdb) p this->name_ $1 = 0x2711e8 "_o73" (gdb) call Tcl::instance().eval("debug 1") 15: lappend auto_path $dbg_library dbg15.3> w *0: application 15: lappend auto_path /usr/local/lib/dbg dbg15.4> Simulator info instances _o1 dbg15.5> _o1 now 0 dbg15.6> # and other fun stuff dbg15.7> _o73 info class Classifier/Addr dbg15.8> _o73 info vars slots_ shift_ off_ip_ offset_ off_flags_ mask_ off_cmn_ dbg15.9> c (gdb) w Ambiguous command "w": while, whatis, where, watch. (gdb) where #0 AddressClassifier::AddressClassifier (this=0x12fbd8) at classifier-addr.cc:47 #1 0x5c68 in AddressClassifierClass::create (this=0x10d6c8, argc=4, argv=0xefffcdc0) at classifier-addr.cc:63 ... (gdb)
The first thing to do if you run out of memory is to make sure you can use all the memory on your system. Some systems by default limit the memory available for individual programs to something less than all available memory. To relax this, use the limit or ulimit command These are shell functions---see the manual page for your shell for details. Limit is for csh, ulimit is for sh/bash.
Simulations of large networks can consume a lot of memory. Ns-2.0b17 supports Gray Watson's dmalloc library (see its web documentation and source code). To add it, install it on your system or leave its source in a directory parallel to ns-2 and specify --with-dmalloc when configuring ns. Then build all components of ns for which you want memory information with debugging symbols (this should include at least ns-2, possibly tclcl and otcl, maybe also tcl).
To use dmalloc:
On some platforms you may need to link things statically to get dmalloc to work. On Solaris this is done with by linking with these options: "-Xlinker -B -Xlinker -static {libraries} -Xlinker -B -Xlinker -dynamic -ldl -lX11 -lXext". (You'll need to change Makefile. Thanks to Haobo Yu and Doug Smith for workign this out.)
We can interpret a sample summary produced from this process on ns-2/tcl/ex/newmcast/cmcast-100.tcl with an exit statement after the 200'th duplex-link-of-interefaces statement:
Dmalloc_summarize must map function names to and from their addresses. It often can't resolve addresses for shared libraries, so if you see lots of memory allocated by things beginning with ``ra='', that's what it is. The best way to avoid this problem is to build ns statically (if not all, then as much as possible).
Dmalloc's memory allocation scheme is somewhat expensive, plus there's bookkeeping costs. Programs linked against dmalloc will consume more memory than against most standard mallocs.
Dmalloc can also diagnose other memory errors (duplicate frees, buffer overruns, etc.). See its documentation for details.
If you have many links or nodes:
KBytes | cmcast-50.tcl(217 Links) | cmcast-100.tcl(950 Links) |
---|---|---|
trace-all | 8,084 | 28,541 |
turn off trace-all | 5,095 | 15,465 |
use array | 5,091 | 15,459 |
remove unnecessay variables | 5,087 | 15,451 |
on SunOS | 5,105 | 15,484 |