Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible memory leak in autorefresh.js #7085

Open
LZTWilliam opened this issue Jan 18, 2024 · 0 comments
Open

Possible memory leak in autorefresh.js #7085

LZTWilliam opened this issue Jan 18, 2024 · 0 comments

Comments

@LZTWilliam
Copy link

Version:

codemirror: 5.65.12
Browser: Chrome 120.0.6099.217 (I believe this problem is browser-irrelevent)

Problem:

Code Analysis: As is shown in code below, when cm.display.wrapper.offsetHeight == 0 the autoRefresh addon register listeners of mouseup/keyup event on window, and continiously check the wrapper's offsetHeight. As soon as the offsetHeight check pass, these listeners will be unregistered.

Abnormal Situation: But under the situation that the offsetHeight of wrapper element is keeps 0 during the whole lifetime of a CodeMirror instance, the listener will never be released, causing the instance be referenced by listener on window, and never be gc'd.

My Case: In my circumstance, I have a dialog contains 2 CodeMirror instance, one of which is hidden by display: none. The dialog and its content is destroyed after closing, and re-create if opened again. So the hidden instance might never be rendered, and the wrapper's offsetHeight keeps 0(I'm using CodeMirror constructor to create instance, BTW).
I believe attempts to destroy instance have no use to this problem. For the stopListening function can only be called by check.

// addon/display/autorefresh.js
CodeMirror.defineOption("autoRefresh", false, function(cm, val) {
  if (cm.state.autoRefresh) {
    stopListening(cm, cm.state.autoRefresh)
    cm.state.autoRefresh = null
  }
  if (val && cm.display.wrapper.offsetHeight == 0)
    startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250})
})

function startListening(cm, state) {
  function check() {

    // >>What if the offsetHeight is always 0 during the whole lifetime of CodeMirror instance?<<
    if (cm.display.wrapper.offsetHeight) {

      stopListening(cm, state)
      if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight)
        cm.refresh()
    } else {
      state.timeout = setTimeout(check, state.delay)
    }
  }
  state.timeout = setTimeout(check, state.delay)
  state.hurry = function() {
    clearTimeout(state.timeout)
    state.timeout = setTimeout(check, 50)
  }
  CodeMirror.on(window, "mouseup", state.hurry)
  CodeMirror.on(window, "keyup", state.hurry)
}

function stopListening(_cm, state) {
  clearTimeout(state.timeout)
  CodeMirror.off(window, "mouseup", state.hurry)
  CodeMirror.off(window, "keyup", state.hurry)
}

My problem can be resolved in some other way (for example, don't instantiate 2 CodeMirror instance). So we can focus on the possible bug itself.
I'm in hurry so can not providing a minimize reproduction demo for now. If you need one please let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant