[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Locals vs. globals redux. Was Re: C-objects with __gc *and* __index?
- From: Rici Lake <lua@...>
- Date: Sun, 7 Aug 2005 12:34:44 -0500
On 7-Aug-05, at 3:46 AM, Uli Kusterer wrote:
First and foremost, I originally just tried the part inside the loop.
When that didn't call the destructor, I thought maybe there's a
threshold for the GC how many objects have to be there to be
considered worth collecting, so I put it a loop around it.
Indeed there is, and 100 iterations is probably not to trigger it. You
must call lua_close(L) in order to get the garbage collector to
finalise all objects when the state is about to be destroyed.
My point was simply that using a global and setting it to nil is not
going to trigger gc any earlier than using a local. (I'm being
influenced here by the globals vs. locals mailing list thread, I
guess.)
That is, in the loop:
for i = 1, 100
local a = Room.new()
end
all of the a's are going to be stored in the same stack slot,
overwriting the previous one, almost exactly the same as the equivalent
C construct:
for (i = 1; i <= 100; i++) {
Room* a = newRoom();
}
with three exceptions:
1) In Lua, unlike C, 'i' is also local to the loop.
2) In Lua, unlike C, overwriting 'a' will not cause a memory leak.
3) Although this particular example doesn't show it, Lua allows 'a' to
be closed into a function closure, in which case it will be reallocated
onto the heap (in effect). A simple meaningless example might help:
log = {}
for i = 1, 100 do
local logi = math.log(i)
log[i] = function(x)
return math.log(x) / logi
end
end
> = log[2](8)
3
> = log[4](8)
1.5
> = log[10](8)
0.90308998699194
Although logi is initially stack allocated, it's use as an unbound
variable in the anonymous function causes it to be evicted to the heap
at the end of each iteration of the for loop, so that it has a
different value for each element of the table 'log'.
While I'm blathering on, note that the unbound variable 'math' in the
anonymous function is a global, since it is unbound in the program;
consequently, it needs to be looked up each time a log function is
called, followed by a table lookup of the key 'log'. This is presumably
unnecessary, and a considerable speed-up can be achieved by simply
looking it up once:
do -- provide a scope for math_log
local math_log = math.log
log = {}
for i = 1, 100 do
local logi = math_log(i)
log[i] = function(x) return math_log(x) / logi end
end
end
It is this speed up that may have motivated the creation of the table
of log functions, rather than simply defining:
function mylog(x, base)
return math.log(x) / math.log(base)
end
Of course, that function could also have been optimised by the same
technique:
do
local math_log = math.log
function mylog(x, base)
return math_log(x) / math_log(base)
end
end