sleyzerzon / soar

Automatically exported from code.google.com/p/soar
1 stars 0 forks source link

justification instantiations don't get retracted #25

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Description From Bob Marinier 2007-09-14 14:57:57 (-) [reply]
Created an attachment (id=93) [details]
Code from Laird that uses up memory until crash.

1) Source the attached code
2) w 0
3) run 100000

Note two things:
- memory usage grows over time
- it takes a while to exit, but there are no unexpected leaks when it does 
so

What's happening is the code generates justifications which immediately
retract.  However, the justification instantiation is not deallocated, and 
this
leaves an extra reference count on the justification production, which then
also does not get deallocated.

Here's what happens in more detail
1) Justification is created with ref count = 1
2) Instantiation of justification is created, which increases ref count to 
2
3) Instantiation is retracted.  During this, the justification is excised,
which brings the ref count back down to 1.
4) The function possibly_deallocate_instantiation is called.  This checks 
if
inst->in_ms is 0 (it is) and inst->preferences_generated is 0 (it is not). 
Since this check fails, the instantiation is not deallocated, and thus the
reference count on the justification production never goes to zero.

What is preferences_generated?

From comments in the code:

preferences_generated:  header for a doubly-linked list of existing
        preferences that were created by this instantiation.
...
Reference counts on instantiations:
      +1 if it's in the match set
      +1 for each preference it created that's still around
   The reference count is kept implicitly using the preferences_generated
   and in_ms fields.  We deallocate an instantiation if its reference count
   goes to 0.

So where are these preferences coming from?  They appear to get generated 
by
the function make_clones_of_results.  The comments there say:

                       Make Clones of Results

   When we build the initial instantiation of the new chunk, we have
   to fill in preferences_generated with *copies* of all the result
   preferences.  These copies are clones of the results.  This routine
   makes these clones and fills in chunk_inst->preferences_generated.

This is where I'm getting stuck -- I don't understand why things are 
getting
cloned, and why they aren't going away later.

Any ideas?
------- Comment #1 From Douglas Pearson 2007-09-14 15:20:53 (-) [reply] ---
----
Is the idea that when the original rule that created the result preference
retracts we need the justification to hold the preference in place--hence 
the
clone?

If that's right the question becomes when the justification is
retracted/excised why don't are cloned preferences removed (step 3 in your
list).
------- Comment #2 From Bob Marinier 2007-09-14 15:53:40 (-) [reply] ------
-
Nobody here seems to understand what the deal with clones is.  But digging
through the code some more I found this:

next_clone, prev_clone:  used for a doubly-linked list of all "clones"
        of this preference.  When a result is returned from a subgoal and a
        chunk is built, we get two copies of the "same" preference, one 
from
        the subgoal's production firing, and one from the chunk 
instantiation.
        If results are returned more than one level, or the same result is
        returned simultaneously by multiple production firings, we can get
        lots of copies of the "same" preference.  These clone preferences
        are kept on a list so that we can find the right one to backtrace
        through, given a wme supported by "all the clones."

...

Reference counts on preferences:
      +1 if the preference is currently in TM
      +1 for each instantiation condition that points to it (bt.trace)
      +1 if it supports an installed context WME

   We deallocate a preference if:
      (1) reference_count==0 and all its clones have reference_count==0
          (hence it couldn't possibly be needed anymore)
   or (2) its match goal is removed from the context stack
          (hence there's no way we'll ever want to BT through it)

...

Possibly_deallocate_preference_and_clones() checks whether a given
   preference and all its clones have reference_count 0, and deallocates
   them all if they do; it returns TRUE if they were actually deallocated,
   FALSE otherwise.   Deallocate_preference() deallocates a given
   preference.  These routines should normally be invoked only via the
   preference_remove_ref() macro.

It looks like possibly_deallocate_preference_and_clones is called from
preference_remove_ref, which is called from lots of places.
------- Comment #3 From Bob Marinier 2007-09-14 16:06:57 (-) [reply] ------
-
Here's a specific example:

The preferences_generated list for justification-1 has two wmes on it, but 
they
are the same wme: S1 ^count 1999999
justification-2 also has two wmes on its preferences_generated list, but 
again
they are the same: S1 ^count 1999998

And so on.
------- Comment #4 From Jonathan Voigt 2009-05-05 16:06:00 (-) [reply] ----

---
look for top state justification compiler symbols, there might be something
hidden in preprocessor code that addresses this
------- Comment #5 From Jonathan Voigt 2009-05-11 12:30:03 (-) [reply] ----

---
Moving to 9.0.2

Original issue reported on code.google.com by voigtjr@gmail.com on 23 Jul 2009 at 4:44

GoogleCodeExporter commented 9 years ago
Code from Laird that uses up memory until crash.

Original comment by voigtjr@gmail.com on 23 Jul 2009 at 4:45

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by voigtjr@gmail.com on 23 Jul 2009 at 5:29

GoogleCodeExporter commented 9 years ago

Original comment by voigtjr@gmail.com on 23 Feb 2010 at 7:43