Why does not the finalizer been called at the end of the first or second for loop?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Why does not the finalizer been called at the end of the first or second for loop?

孙世龙 sunshilong
Hi, list

Here are the related code snippets(for your convenient, see ):
mt = {__gc = function (o) print("gc:",o[1], o[2]) end}

--[[
list1 = {1, nil  }
list2 = {2, list1}
list3 = {3, list2}
list4 = {4, list3}
list5 = {5, list4}
--]]
list = nil
for i = 1,5 do
list = setmetatable({i, link = list}, mt)
end

::BEGIN::
for k,v in pairs(list) do
print("key=",k,"value=",v)
if(k == "link") then
print "==========="
if(v ~= nil) then
list = v
collectgarbage()
goto BEGIN;
end
end
end

Here are the outputs:

key= 1 value= 5
key= link value= table: 0x55b1c39c0630
--Question:
--                Why does not the finalizer been called here after
"list = v" has been invoked?
--                For the former variable "list" is still referenced
by "k,v in pairs(list)"?
--                If the guess aforementioned is right, why does not
the finalizer been called in the next loop?
===========
key= 1 value= 4
key= link value= table: 0x55b1c39c8e30
===========
gc: 5 nil
key= 1 value= 3
key= link value= table: 0x55b1c39c85e0
===========
gc: 4 nil
key= 1 value= 2
key= link value= table: 0x55b1c39c8860
===========
gc: 3 nil
key= 1 value= 1
gc: 2 nil
gc: 1 nil

Thank you for your attention to my question.
Best regards.

Sunshilong
Reply | Threaded
Open this post in threaded view
|

Re: Why does not the finalizer been called at the end of the first or second for loop?

Gé Weijers
On Mon, Oct 19, 2020 at 1:33 AM 孙世龙 sunshilong <[hidden email]> wrote:
> --Question:
> --                Why does not the finalizer been called here after
> "list = v" has been invoked?
> --                For the former variable "list" is still referenced
> by "k,v in pairs(list)"?
> --                If the guess aforementioned is right, why does not

you call 'collectgarbage' in the for loop. "pairs" returns the
function "next", its parameter (list), and nil. The for loop will keep
the 'list' value on the stack until you exit the loop. So "list = v"
does not make the old value of 'list' unreachable, and collectgarbage
cannot collect the value yet. All of this is easy to figure out from
the definition of "pairs" and the description of the for loop in the
Lua manual.






--

Reply | Threaded
Open this post in threaded view
|

Re: Why does not the finalizer been called at the end of the first or second for loop?

孙世龙 sunshilong
>The for loop will keep
>the 'list' value on the stack until you exit the loop. So "list = v"
>does not make the old value of 'list' unreachable, and collectgarbage
>cannot collect the value yet.
You could see that the old value of 'list' is freed in later loop
indeed(there are outputs that contain "gc:").
Here are the outputs:
key= 1 value= 5
key= link value= table: 0x55b1c39c0630
===========
key= 1 value= 4
key= link value= table: 0x55b1c39c8e30
===========
gc: 5 nil                                               ---Attention
here! It's freed at here, not at the previous loop.
key= 1 value= 3
key= link value= table: 0x55b1c39c85e0
===========
gc: 4 nil
key= 1 value= 2
key= link value= table: 0x55b1c39c8860
===========
gc: 3 nil
key= 1 value= 1
gc: 2 nil
gc: 1 nil

On Tue, Oct 20, 2020 at 10:30 PM Gé Weijers <[hidden email]> wrote:

>
> On Mon, Oct 19, 2020 at 1:33 AM 孙世龙 sunshilong <[hidden email]> wrote:
> > --Question:
> > --                Why does not the finalizer been called here after
> > "list = v" has been invoked?
> > --                For the former variable "list" is still referenced
> > by "k,v in pairs(list)"?
> > --                If the guess aforementioned is right, why does not
>
> you call 'collectgarbage' in the for loop. "pairs" returns the
> function "next", its parameter (list), and nil. The for loop will keep
> the 'list' value on the stack until you exit the loop. So "list = v"
> does not make the old value of 'list' unreachable, and collectgarbage
> cannot collect the value yet. All of this is easy to figure out from
> the definition of "pairs" and the description of the for loop in the
> Lua manual.
>
> Gé
>
>
>
>
> --
> Gé
Reply | Threaded
Open this post in threaded view
|

Re: Why does not the finalizer been called at the end of the first or second for loop?

Gé Weijers


On Tue, Oct 20, 2020, 19:16 孙世龙 sunshilong <[hidden email]> wrote:
>The for loop will keep
>the 'list' value on the stack until you exit the loop. So "list = v"
>does not make the old value of 'list' unreachable, and collectgarbage
>cannot collect the value yet.
You could see that the old value of 'list' is freed in later loop
indeed(there are outputs that contain "gc:").
Here are the outputs:
key= 1 value= 5
key= link value= table: 0x55b1c39c0630
===========
key= 1 value= 4
key= link value= table: 0x55b1c39c8e30
===========
gc: 5 nil                                               ---Attention
here! It's freed at here, not at the previous loop.

This is the first time collectgarbage is called when the program does not reference the table with key 5 anymore, so the finalizer can be called. The call to __gc is done once the collector determines that the table is no longer referenced.
The loop keeps a reference of the value passed to 'pairs' which disappears when the goto statement executes. 


key= 1 value= 3
key= link value= table: 0x55b1c39c85e0
===========
gc: 4 nil
key= 1 value= 2
key= link value= table: 0x55b1c39c8860
===========
gc: 3 nil
key= 1 value= 1
gc: 2 nil
gc: 1 nil

On Tue, Oct 20, 2020 at 10:30 PM Gé Weijers <[hidden email]> wrote:
>
> On Mon, Oct 19, 2020 at 1:33 AM 孙世龙 sunshilong <[hidden email]> wrote:
> > --Question:
> > --                Why does not the finalizer been called here after
> > "list = v" has been invoked?
> > --                For the former variable "list" is still referenced
> > by "k,v in pairs(list)"?
> > --                If the guess aforementioned is right, why does not
>
> you call 'collectgarbage' in the for loop. "pairs" returns the
> function "next", its parameter (list), and nil. The for loop will keep
> the 'list' value on the stack until you exit the loop. So "list = v"
> does not make the old value of 'list' unreachable, and collectgarbage
> cannot collect the value yet. All of this is easy to figure out from
> the definition of "pairs" and the description of the for loop in the
> Lua manual.
>
> Gé
>
>
>
>
> --
> Gé
Reply | Threaded
Open this post in threaded view
|

Re: Why does not the finalizer been called at the end of the first or second for loop?

孙世龙 sunshilong
>The loop keeps a reference of the value passed to 'pairs' which disappears when the goto statement executes.


^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Not after the statement executed?

On Wed, Oct 21, 2020 at 11:51 AM Gé Weijers <[hidden email]> wrote:

>
>
>
> On Tue, Oct 20, 2020, 19:16 孙世龙 sunshilong <[hidden email]> wrote:
>>
>> >The for loop will keep
>> >the 'list' value on the stack until you exit the loop. So "list = v"
>> >does not make the old value of 'list' unreachable, and collectgarbage
>> >cannot collect the value yet.
>> You could see that the old value of 'list' is freed in later loop
>> indeed(there are outputs that contain "gc:").
>> Here are the outputs:
>> key= 1 value= 5
>> key= link value= table: 0x55b1c39c0630
>> ===========
>> key= 1 value= 4
>> key= link value= table: 0x55b1c39c8e30
>> ===========
>> gc: 5 nil                                               ---Attention
>> here! It's freed at here, not at the previous loop.
>
>
> This is the first time collectgarbage is called when the program does not reference the table with key 5 anymore, so the finalizer can be called. The call to __gc is done once the collector determines that the table is no longer referenced.
> The loop keeps a reference of the value passed to 'pairs' which disappears when the goto statement executes.
>
>
>> key= 1 value= 3
>> key= link value= table: 0x55b1c39c85e0
>> ===========
>> gc: 4 nil
>> key= 1 value= 2
>> key= link value= table: 0x55b1c39c8860
>> ===========
>> gc: 3 nil
>> key= 1 value= 1
>> gc: 2 nil
>> gc: 1 nil
>>
>> On Tue, Oct 20, 2020 at 10:30 PM Gé Weijers <[hidden email]> wrote:
>> >
>> > On Mon, Oct 19, 2020 at 1:33 AM 孙世龙 sunshilong <[hidden email]> wrote:
>> > > --Question:
>> > > --                Why does not the finalizer been called here after
>> > > "list = v" has been invoked?
>> > > --                For the former variable "list" is still referenced
>> > > by "k,v in pairs(list)"?
>> > > --                If the guess aforementioned is right, why does not
>> >
>> > you call 'collectgarbage' in the for loop. "pairs" returns the
>> > function "next", its parameter (list), and nil. The for loop will keep
>> > the 'list' value on the stack until you exit the loop. So "list = v"
>> > does not make the old value of 'list' unreachable, and collectgarbage
>> > cannot collect the value yet. All of this is easy to figure out from
>> > the definition of "pairs" and the description of the for loop in the
>> > Lua manual.
>> >
>> > Gé
>> >
>> >
>> >
>> >
>> > --
>> > Gé
Reply | Threaded
Open this post in threaded view
|

Re: Why does not the finalizer been called at the end of the first or second for loop?

Gé Weijers
On Tue, Oct 20, 2020 at 11:28 PM 孙世龙 sunshilong <[hidden email]> wrote:
>
> >The loop keeps a reference of the value passed to 'pairs' which disappears when the goto statement executes.
>
>
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Not after the statement executed?

The effect of a "goto" that exits a block like this is twofold:
- any explicit or implicit local variables that go out of scope are
destroyed. The objects that they refer to are not destroyed (but any
"__close" methods are called).
- the program continues at the target label.

The way this works: the Lua 5.4 interpreter translates the "goto
BEGIN" into two VM instructions:
CLOSE 0
JMP -22

"CLOSE 0" destroys all local variables, in this case the 3 loop
variables containing the "next" function, the value of "list" when the
loop was entered, and the current value of "k". This happens after
"collectgarbage" is called, so the previous value of "list" is still
reachable. This causes the delay.

When exactly all this happens is not all that relevant, it has not
happened before the goto is executed, and by the time the loop is
entered again it has. If the Lua compiler was sufficiently "clever" it
could even conclude that the 3 loop variables are no longer needed
right after "list = v" and destroy them right there.

In general you should not rely on the timing of the call to "__gc"
because it may change between Lua versions. A change would be legal
because the exact behavior is not specified in the spec. Because
"__gc" is called at an unknown point in the execution of your program
its use is a bit dangerous, it's best not to change anything outside
of the object about to be collected.