lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I'm having trouble figuring out why I'm holding on to a bunch of
memory, even after calling collectgarbage(). I'll describe the problem
and show the confusing results, in hopes that there is a known reason
that someone can share. I'll also make a minimal example, in the mean
time.

I need to implement a simple caching mechanism to avoid "getting"
resources from C libraries that I'm binding to. These libraries often
use reference counting.

In my testing, I wrote a mock "filter" that creates a table with 2 ^16
random numbers in it, along with an "id" field, which is a new table
that I'm using as a uuid. To simulate reference counting, the filter
has a "reference" table, which is a hash where the "id" (the same
table as in the object) is the key and the count (number) is the
value. When count == 0, I set that id to `nil`, so there is no longer
a reference.


during teardown, I'm seeing the following:
```lua
print("starting size:",collectgarbage("count"))
--> starting size:  810.0546875 56

--: The main object...
r = Resource()

---: do stuff here, including:
---: make a filter object that knows how to free,  clone and get an object.
---: As part of the reference count, it stores a hash of [object id] =
reference_count_integer
---: Make 20 values with a big random number table in it...

print("before nilling",collectgarbage("count"))
--before nilling 5690.0771484375 79

r = nil
collectgarbage()
--: __gc method is called, which reports and shows that everything is
being properly "niled"

print("nilled r:",collectgarbage("count"))
--> nilled r: 2616.2177734375 223
--: This is about exactly half of what I would expect to "go away"

--Let's look to see if there is anything in the reference table that
didn't get nil-ed.
--NOTE: pt pretty prints a value
pt(filter.references)
--{} --empty table
pt("metatable to muck with things?", getmetatable(filter.references))
--metatable to muck with things? nil --no metatable

filter.references = nil
print(collectgarbage())
print("niled references: size",collectgarbage("count"))
--> niled references: size 547.14453125 148

```
The last returned size is what I would have expected after setting r
to nil. What is even weirder is that I can delete *any* of the three
fields inside of "filter", two of which are functions, and I get the
same result: all expected memory is freed and I'm down to around 547k.

I'm trying to figure out why deleting a field from this "filter" table
releases the "other half" of the allocated memory and why it's hanging
around in the first place. I'm certain that I'm not referencing
"filter" table outside of the "r" object that I've already set to nil
and which I've verified as being collected (using print statements in
its __gc method). I'm not sure how that would matter anyway.

So, I'm sure I'm overcomplicating things, but can anyone see through
to what might be the issue?

-Andrew