Jump to content


Photo

Garbage collector should resolve circular references


  • Please log in to reply
8 replies to this topic

#1 fragman

fragman
  • Members
  • 1591 posts

Posted 18 July 2012 - 08:54 AM

This is documented behavior, but I consider it a bug or at least a serious limitation so I'm posting here.
Simple demonstration that quickly increases memory usage (and thus should be killed quickly):
While(true)
{
a := {}
b := {a : a}
a.b := b
}
Is there a technical or logical reason that circular references aren't resolved? I recently had a problem due to improper use of a Delegate class which caused leaks because of this behavior.

I believe that an algorithm like the following should work, please correct me if I'm wrong:
[*:3bvqtyx2]Create a list of all existing objects
[*:3bvqtyx2]For all objects referenced in global, static and local variables, recursively traverse their keys/values and remove all referenced objects from the list
[*:3bvqtyx2]All objects that are still on the list aren't reachable by script and may be deleted if they don't have an increased ref count by ObjAddRef()

#2 HotKeyIt

HotKeyIt
  • Fellows
  • 6132 posts

Posted 18 July 2012 - 05:34 PM

You could simply save your objects in another object:
A:=[]

While(true)

{

  A.a := {}

  A.b := {a : a}

  A.a.b := b

}


#3 fragman

fragman
  • Members
  • 1591 posts

Posted 18 July 2012 - 07:40 PM

"a" and "b" are undefined in your code. If I assume that you meant to write A.a and A.b instead you get the same behavior as in the original post.
It's clear that there are workarounds, such as manually decreasing the reference count of an object, though I'm unsure how an invalid object reference would behave.
The point is that this can easily lead to memory leaks if the programmer isn't aware of this behavior.

#4 HotKeyIt

HotKeyIt
  • Fellows
  • 6132 posts

Posted 18 July 2012 - 07:57 PM

That is true, probably it should be noted in several places in help if it can't be fixed.

#5 Lexikos

Lexikos
  • Administrators
  • 8850 posts

Posted 18 July 2012 - 10:07 PM

Resolving the circular reference problem would take far more work than I'm willing to put in any time soon.

There can also be references:
[*:38w0hnxa]on the expression evaluation stack, such as any time you return an object from a function or another object. For instance, x.y.z() and z(x.y) keep x.y on the stack while z() is running. This stack is simply a local variable of Line::ExpandExpression(), so multiple instances of it may exist at unknown locations on the regular call stack.
[*:38w0hnxa]in temporary (C++) variables, such as in the code that implements for-loops.

All objects that are still on the list aren't reachable by script and may be deleted if they don't have an increased ref count by ObjAddRef()

The whole point of the garbage collector would be to detect objects which have a non-zero reference count but really have no accessible references. This condition would defeat the purpose of the garbage collector, unless a separate "lock" mechanism is put in place to prevent an object from being freed while external code has a reference to it. (This would bring back the problem of circular references on a smaller scale.)

probably it should be noted in several places

Such as?

#6 HotKeyIt

HotKeyIt
  • Fellows
  • 6132 posts

Posted 19 July 2012 - 04:49 AM

Such as?

Probably here in Remarks and add remarks here too.
And probably it should be noted at the top of Objects page, something like

An object in AutoHotkey is an abstract data structure which provides three basic functions:

GET a value.
SET a value.
CALL a method (that is, a function which does something with the target object).

An object reference is a pointer or "handle" to a particular object. Like strings and numbers, object references can be stored in variables, passed to or returned from functions and stored in objects. After copying a reference from one variable to another as in x := y, both variables refer to the same object. Please note, circular references must be broken before an object can be freed.



#7 Lexikos

Lexikos
  • Administrators
  • 8850 posts

Posted 19 July 2012 - 07:51 AM

I think it is neither simple enough for a beginner to understand nor common or critical enough to be worth mentioning in the basic introduction and several sections on the one page. There are already enough complaints that the object documentation is difficult to understand.

Perhaps there can be a "Freeing Objects" section under "Basic Usage". I've seen several posts asking about freeing objects, so providing a clear and simple explanation might help. This section can mention the circular reference problem and link to the "Reference-Counting" section.

#8 MasterFocus

MasterFocus
  • Moderators
  • 4131 posts

Posted 19 July 2012 - 08:31 AM

Perhaps there can be a "Freeing Objects" section under "Basic Usage". I've seen several posts asking about freeing objects, so providing a clear and simple explanation might help. This section can mention the circular reference problem and link to the "Reference-Counting" section.

+1
I'm not using AHK_L (+objects) yet, but I've been watching this thread and I suppose it's the best approach so far for mentioning this. Just my 2 cents :)

#9 HotKeyIt

HotKeyIt
  • Fellows
  • 6132 posts

Posted 19 July 2012 - 09:06 AM

Sounds good :)