home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / mac / MAC / Programming Stuff / Macintosh Debugging / Leaks / Leaks Read Me < prev    next >
Encoding:
Text File  |  1991-09-12  |  14.6 KB  |  192 lines  |  [TEXT/MPS ]

  1.  
  2.  
  3.                                                             Leaks:
  4.                                                 a dcmd to help find memory leaks
  5.                                                         
  6.                                                         from Bo3b Johnson
  7.                                                             MS 37-DS
  8.                                                         
  9.                                                             10/17/90
  10.                                                             
  11. Release Notes:
  12.  
  13.         What leaks are:
  14.             Memory leaks are those problems in programs where a Handle or a Ptr are allocated but never
  15.             disposed.  This sort of problem is hard to track down, because programs typically  allocate a
  16.             ton o' blocks while they work.  If a block is not disposed over a given operation, you usually build
  17.             up more and more of these orphaned blocks until the program runs out of memory.  'Properly
  18.             written Macintosh programs will run for hours, even days, without crashing.'  To point out the
  19.             reason why these are such good bugs to solve before shipping, consider what would happen if all
  20.             the windows that were allocated in a program were never disposed...
  21.         
  22.             Historically, the way to spot leaks has been to do a heap dump and watch if free space keeps going 
  23.             down.  This doesn't tell you where the leak is, but it lets you see the blocks that are repetitious, and 
  24.             it tells you that there is a leak somewhere.
  25.         
  26.         How to install:
  27.             What I've done here is to make a tool to spot leaks, now in it's second incarnation as a dcmd.  
  28.             Previously it was seriously skanky by being built in three separate code resources.  Only a few
  29.             people had the pleasure of using version 1.  This version is a happy dcmd, and is completely
  30.             contained in the one dcmd resource.  Paste it into your debugger prefs, reboot, and away you go.
  31.         
  32.         Basic operation:
  33.             1) Launch the application you want to examine.  This sets up the long term storage that the app
  34.             needs, and this tool can't help find leaks during a startup time.
  35.             2) Turn the watching code on by 'Leaks On'.  It will cough out some info that is marginally helpful,
  36.             like the maximum number of blocks it can watch at one time.  This is hard coded right now to
  37.             be 500 blocks.
  38.             3) Go, then exercise the program in question.  In order to differentiate between a memory leak, and
  39.             something that just hangs around for a long time, I need you to run the sequence in question three
  40.             or more times.  As an example, open and close a document three times.
  41.             4) Break into Macsbug, and do a 'Leaks Off'.  This turns off the watching code, and has it analyze the
  42.             info it collected to see if there is a series of blocks (3 or more) that look like they might be a leak.  If
  43.             something looks right, it will give you a minor stack crawl of how a block was allocated.  The block
  44.             address, and size are also displayed so you can check it out further.  The 'matches' field tells you 
  45.             how many blocks match the one being displayed, in terms of size and stack crawl.
  46.                     
  47.         Other options:
  48.             It has your basic help for a dcmd, and has 4 options.
  49.             Leaks On- Turns on the watching code, so it will track every NewHandle/NewPtr
  50.                 DisposHandle/DisposPtr that the system does, including the system heap, and all heaps
  51.                 anywhere.  It also clears out the b-tree I use to watch for blocks, zeroing the whole tree.
  52.             Leaks Off- Turns off the code, but leaves the b-tree intact.  It will analyze the entire tree to
  53.                 see if there are several blocks that are the same size, allocated from the same piece of code.
  54.                 If there are 3 or more candidates, it is considered a leak and displayed.  
  55.             Leaks Dump- Dumps out every element in the b-tree, giving the address of the block being 
  56.                 watched, the size, and the stack crawl for who allocated the block.  This isn't terribly helpful,
  57.                 but can give you each block being tracked with no filtering.
  58.             Leaks- If you just type the command with no option, it will leave the watching state as is, but
  59.                 will do the tree analysis looking for leaks, and displaying likely candidates.  This is sort of a
  60.                 status mode, in case you aren't sure if something is leaking and don't want to change the 
  61.                 watching state.
  62.             In each case, it will also dump out the header information so that you can see the state of the
  63.             watcher.  This includes info like the number of memory blocks it is currently watching, and 
  64.             the watching state itself (either on or off).  This also gives you that vital feedback to let you
  65.             know that something happened in response to the command.
  66.                 
  67.             Another way to use this tool would be to embed DebugStr commands in your program, surrounding
  68.             an area that should be checked.  You can do a 'Leaks On; g' at the start of some operation, and
  69.             do a 'Leaks Dump' at the end.  If you are sure that no memory should be left around over a 
  70.             given piece of code, then my tracking tree should be empty.  If it isn't, then any block that is
  71.             displayed would be a likely leak.  Another way to use the tool would be to turn it on and 
  72.             exercise the application for a longer time, not making any effort to do operations three times.
  73.             Presumably, if there are leaks, then the leaking section of code will get hit several times 
  74.             during normal operation, satisfying the three or more criteria.  This can give you a larger 
  75.             number of potential leaks to examine, but if the tool identifies some candidates during that
  76.             time, they are at least worth looking at.
  77.  
  78.         Ways to fake me out:
  79.             -If you turn on Leaks and then launch an app, you are sure to create a bunch of blocks, and quite
  80.             possibly some of them will have the same size and stack crawl.  I'll tag them as a likely leak, but
  81.             it is probably fine.  In addition, if you launch something like MPW, you will quite likely run out
  82.             of records in the free list, causing me to DebugStr to let you know.  It is unlikely that I can give
  83.             you good information during a launch, so I recommend turning leaks on after the app is started.
  84.             -If you turn on Leaks, launch an app, then quit, then launch again.  When apps quit they typically
  85.             don't clean up their blocks, and I don't catch the application leaving yet.  When the app is 
  86.             relaunched, the same blocks will probably get allocated, frying my b-tree because it will have two
  87.             records watching the same block.  When the tool is turned on or off I check the tree for consistency
  88.             and bitch about blocks or other bad things that may have happened to the tree.  Reinitialize the
  89.             tree by doing a Leak On, to clear the error state.
  90.             -If you watch a bunch of blocks, in the 300 block range, it is entirely possible that I will overflow the
  91.             Macsbug stack when displaying the info.  Macsbug will let you know.  This usually happens only
  92.             when an app gets launched.
  93.             -If a code block moves around a lot, I may not see a memory leak that I should.  This is because the
  94.             stack crawl could be different each time the block was allocated.  This is sort of unlikely since
  95.             most programs tend to be consistent, but it is possible.  
  96.             
  97.         If you're using TMon Pro:
  98.             You have to have the latest version of TMon Pro, the b2238 version doesn't work with this 
  99.             dcmd.  I added a call to dcmdSwapWorlds so that I patch the traps in the mac world, instead of
  100.             in the TMon world.  It seems to work fine from that point.  This is slightly more risky in TMon
  101.             than in Macsbug, since I install tail patches in this case.  For the macsbug case, the patches I make
  102.             come in before system patches, so the tail patch problem is gone.  Since TMon comes in at
  103.             init time, after the system patches, I will patch traps that may disable a system bug fix.  I don't
  104.             believe there is any conflict on any machine today, but I haven't looked that hard.  
  105.             
  106.         How it works:
  107.             At Macsbug     load time, before system patches, the dcmd gets called to do
  108.             it's Init.  The Init patches the four traps that are deemed handy: NewHandle/NewPtr/
  109.             DiposHandle/DisposPtr, and allocates a big pointer in the system heap that is filled with records
  110.             that track individual memory blocks.  The block is about 28K in size, and is set up to watch
  111.             500 possible allocations.  The block is cleared, and setup as a linked list of empty records, waiting
  112.             to be added to the b-tree.  The b-tree is the data structure that does all the work in terms of 
  113.             keeping track of things.  When a block is allocated by anybody in the system, my trap patch
  114.             gets called.  That patch saves off the size of the block, the address that came back, and an 8
  115.             level stack crawl to keep track of where a block was allocated.  If the stack crawl cannot go 
  116.             back a full 8 levels, the remaining entries are zero.  All this info is saved into one
  117.             of these records in my pointer block, and the record is moved out of the empty list and into
  118.             the b-tree list.  When the record is added to the b-tree list, it is sorted into the tree using the
  119.             address of the block being watched.  I use a binary tree so that the watching code can run 
  120.             without slowing the machine down, like it would if I were using a linear list.  All blocks that
  121.             are actively being watched are in the b-tree as separate records.  The rest of the 500 records
  122.             are in the empty list, and are available.  The heads of both lists are shown when you do any
  123.             command.  When a block is deallocated by a program, it will call something like DisposHandle,
  124.             and the trap patch will catch that too.  It sees the handle being disposed, and looks in the b-tree
  125.             for a matching record.  If it finds it, it will futz around with the b-tree to keep it nicely set up,
  126.             but remove the record from the tree.  It zeros the record, and adds it back into the free list.
  127.             The records are thus reused all the time.  Any block that was allocated but not yet disposed
  128.             will be in the b-tree.  That's about it.  When you turn the watching tool
  129.             off, or check its status, it will do the analysis of the tree.  This involves driving the entire tree
  130.             many times trying to find a series of blocks that have the same size, and were allocated by the
  131.             same sequence of code (the stack crawl is the same).  This is presumed to indicate a leak, since
  132.             I don't expect a given sequence of code to keep allocating blocks without throwing them away.
  133.             The analysis routine requires that there be 3 or more of the blocks in the b-tree that have the
  134.             same size and stack crawl.  It will dump an example candidate if it finds one.  If no blocks
  135.             qualify, then it won't display anything (but you see the header).  There may be tons of blocks 
  136.             that it is actively watching, but few of them are tagged as likely to be leaks.  If you run it for
  137.             long enough, you may create more than 500 blocks that I would be watching.  If I run out of
  138.             records, I'll DebugStr to let you know.  Whenever the Leaks code is called, I do a treewalk
  139.             to be sure the b-tree is in a valid state.  This involves making sure that there aren't two
  140.             records in the tree with the same address (impossible for two blocks to be allocated with
  141.             the same address), and that I have the 500 blocks when both lists are taken into account.
  142.             If something went wrong, I'll let you know by writing the information to Macsbug. 
  143.             
  144.  
  145.         Theory of operation:
  146.             Trying to find memory leaks is a problem that cannot be solved in a completely deteriministic
  147.             way.  The Macintosh makes it difficult to track memory usage, and provides no support for
  148.             finding if a block is in use or not.  Given the constraints, I chose to make the tool work in a 
  149.             heuristic way: I ask the user to do a given operation three or more times.  If a given operation is
  150.             leaking memory, then each time it is activated, you should get another block or two on the
  151.             heap.  Doing the operation three times makes it possible to differentiate between blocks that
  152.             are persistent (allocated once and left around), and blocks that are being lost.  An example of
  153.             persistent data would be the CODE 1 resource in most applications.  It is allocated once at the
  154.             beginning of a program and not disposed until the app quits.  There may be unrecognizable 
  155.             data that the app creates at startup time as well, something not related to resources.  Blocks of
  156.             this form are hard to differentiate from blocks allocated later.  By doing the operation three
  157.             times, I can look for things that are repetitive, and thus differentiate things that are showing
  158.             up as data that is not being disposed.  This approach means that I cannot find leaks that only
  159.             happen once, like blocks leaked during an application startup.  I am not particularly concerned
  160.             about those leaks, since they are 'only' wasting memory.  Those type of leaks won't cause the
  161.             system to crash, as a repetitive leak will.  The analysis code merely looks through the saved
  162.             information to find three or more blocks that have the same size, and were allocated from 
  163.             the same sequence of code.  This critieria can obviously fail in some circumstances, since
  164.             there may be a sequence of code that allocates a number of blocks that look alike.  An example
  165.             might be a spot in the program where it loads in a number of resources.  Since a series of 
  166.             GetResource calls will allocate memory, you could get a false reading that there is a leak.  I've
  167.             solved that specific example by ensuring that the blocks that are possible leaks are not
  168.             recognized by the resource manager before I use them as leak candidates.  There are a number
  169.             of similar situations where I cannot discern the difference.  In practical terms, this means the
  170.             leak display is showing potential leaks, not sure leaks.  The human still has to look at the
  171.             results.  By doing this operation though, I have trimmed down the number of blocks to look
  172.             at, and in a lot of cases, I trim the number to zero.  You can see memory leaks by looking at a 
  173.             heap dump, but this isn't the most efficient way.  This tool should make it relatively painless 
  174.             to find leaks.   There is the other side to the problem of filtering the block information though,
  175.             and that is the possibility of filtering out blocks that actually are leaks, and thus not 
  176.             reporting one that has been leaked.  This is the certainly the case for one-time leaks, like 
  177.             during startup.  Given a relatively discrete operation, you shouldn't run into this problem.
  178.             The only way I can currently see it happening is if a block is allocated from a code segment
  179.             that keeps moving around in memory.  Most applications don't have code segments that
  180.             are actually  in a different location every time they allocate memory; but it is possible.  
  181.             
  182.             
  183.             As always, if you find bugs in this software, let me know.  In fact, tell me what you think.
  184.             If you hate it, or like it, I would be interested in knowing.  There are a number of tools of
  185.             this form that I could make, so feedback is helpful.  I made this one because I wanted an
  186.             easier way to find memory leaks.  If you find it useful, let me know.  If you have ideas
  187.             for improvement, those are welcome too.
  188.                 Bo3b. 
  189.         
  190.             
  191.         
  192.