Skip to content

Python-object is not garbage collected when used with EventListener #693

@phorward

Description

@phorward

Hi!

I have a special case here regarding garbage collection in combination with JavaScript's addEventListener and removeEventListener functions.

  1. Creating an instance of a class, associating it with a DOM element and removing it again works - the object is entirely freed.
  2. Creating an instance of a class, associating it with a DOM element, attaching an event to it and detaching it immediately after still holds a reference to it the object, even if it is explicitly removed with del

I guess, that the problem here is in JavaScript, which still holds a reference and this is normal with JavaScript. But I'm quite unsure, and would like to ask for further investigation, eventually its really a bug.

Test case is this Python script. Attached is bug.txt
to be renamed bug.html, which can be copied into the build/ folder and directly be executed.

from js import document
import weakref, gc

print("start")

class TestWrapper:
    def __init__(self):
        super().__init__()
        self.div = document.createElement("div")

    def testCallback(self, event):
        print("Got Event")

    def attach(self):
        print("attach")
        self.div.addEventListener("click", self.testCallback)

    def detach(self):
        print("detach")
        self.div.removeEventListener("click", self.testCallback)

    def __del__(self):
        print("I am removed")

print("---111---")

div = TestWrapper()
rw = weakref.ref(div)
gc.collect()
print("1 Weakref resolves to: %s" % rw())
del div
gc.collect()
print("1 Weakref after dropped reference resolves to: %s" % rw())  # << this is None, as expected!

print("---222---")

div = TestWrapper()
rw = weakref.ref(div)
div.attach()
del div
gc.collect()
print("2 Weakref to Wrapper-Class with active event listener: %s" % rw())
rw().detach()
gc.collect()
print("2 Weakref to Wrapper-Class with removed event listener: %s" % rw())  # << At least this should be None

The logging output in the JavaScript console is this:

Python initialization complete
start
---111---
1 Weakref resolves to: <TestWrapper object at 0x9a8a60>
I am removed
1 Weakref after dropped reference resolves to: None
---222---
attach
2 Weakref to Wrapper-Class with active event listener: <TestWrapper object at 0x9a8a60>
detach
2 Weakref to Wrapper-Class with removed event listener: <TestWrapper object at 0x9a8a60>

It can be reproduced both in Firefox 77.0.1 and Chromium Version 83.0.4103.97

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions