The memory usage reported by guppy differ from ps command
possibly due to swapping/memory reservation, based on ps's definition:
RSS: resident set size, the non-swapped physical memory
that a task has used (in kiloBytes).
VSZ: virtual memory usage of entire process.
vm_lib + vm_exe + vm_data + vm_stack
it can be a bit confusing, 4 different size metrics can be seen with:
# ps -eo pid,vsz,rss,sz,size,cmd|egrep python
PID VSZ RSS SZ SZ CMD
23801 4920 2896 1230 1100 python
the virtual size includes memory that was reserved by the process and not used, the size of all shared libraries that were loaded, pages that are swapped out, and blocks that were already freed by your process, so it could be much larger than the size of all live objects in python.
some additional tools to investigate memory performance:
Heapy (part of Guppy, which you are using): http://guppy-pe.sourceforge.net/
Python Memory Validator http://www.softwareverify.com/python/memory/index.html
PySizer http://pysizer.8325.org/
good guide on tracking down memory leaks in python using pdb and objgraph:
http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks
As pointed out above the RSS size is what you're most interested in here. The "Virtual" size includes mapped libraries, which you probably don't want to count.
It's been a while since I used heapy, but I am pretty sure the statistics it prints do not include overhead added by heapy itself. This overhead can be pretty significant (I've seen a 100MB RSS process grow another dozen or so MB, see http://www.pkgcore.org/trac/pkgcore/doc/dev-notes/heapy.rst ).
But in your case I suspect the problem is that you are using some C library that either leaks or uses memory in a way that heapy does not track. Heapy is aware of memory used directly by python objects, but if those objects wrap C objects that are separately allocated heapy is not normally aware of that memory at all. You may be able to add heapy support to your bindings (but if you do not control the bindings you use that is obviously a hassle, and even if you do control the bindings you may not be able to do this depending on what you are wrapping).
If there are leaks at the C level heapy will also lose track of that memory (RSS size will go up but heapy's reported size will stay the same). Valgrind is probably your best bet to track these down, just as it is in other C applications.
Finally: memory fragmentation will often cause your memory usage (as seen in top) to go up but not down (much). This is usually not that much of a problem with daemons, since the process will reuse this memory, it's just not released back to the os, so the values in top do not go back down. If memory usage (as seen by top) goes up more or less linearly with the number of users (connections), does not go back down, but also does not keep growing forever until you hit a new maximum number of users, fragmentation is probably to blame.