Opened 4 years ago

Last modified 14 months ago

#10689 open bug

Tooltip memory leak - endless DOM appending

Reported by: DysprosiumDy Owned by:
Priority: minor Milestone: none
Component: ui.tooltip Version: 1.11.2
Keywords: Cc:
Blocked by: Blocking:

Description

When a tooltip is created, a hidden <div> with the class "ui-helper-hidden-accessible" is appended to the body. This <div> holds another <div> in which the contents of the tooltip is placed. However, this inner <div> is set to "display: none;" and is not being removed when the tooltip hides. This results in the "ui-helper-hidden-accessible" <div> from expanding endlessly, causing a major memory leak on pages with big tooltips.

jsFiddle http://jsfiddle.net/ahk9d5cf/

In this reduced test case I have changed the CSS of the ui-helper-hidden-accessible and its inner divs so that it becomes visible, making the problem easier to notice.

  • This bug has been reproduced using jQuery UI 1.11.2 and 1.11.0. Other versions have not been tested.
  • This bug even occurs on the jQuery UI Tooltip demo page itself. A simple inspection of the page shows this.
  • This bug has been reproduced in both Firefox 32 and Chrome 38.

Change History (15)

comment:1 Changed 4 years ago by Scott González

Resolution: notabug
Status: newclosed

Technically this isn't a bug. The "leak" goes away if you destroy the tooltip. If the content is so large that it's causing major memory problems for you, perhaps you should reconsider whether the content you're displaying is actually a tooltip.

comment:2 Changed 4 years ago by DysprosiumDy

Hey Scott,

How is this not a bug? What is the purpose of having a copy of the entire contents of the tooltip in the DOM until the tooltip is destroyed? In a web app that is built to stay open for a very long time, the useless divs pile up to absurd quantities. Now, if there's a particular purpose for this behavior, then I'd love to hear what it is.

We have a tooltip that's a table with some information, styled. We have tooltips like that scattered all over the page. Each time a tooltip is hovered, even if just for split second, causes a complete copy of that table to be inserted into the DOM. Over time, this can build up to silly memory usage.

But yeah. Can you explain what the purpose of this behavior is? It was introduced in a recent version of jQuery UI (I suspect 1.11) and it's big enough for me to have to regress to a previous version.

Kind regards, Dys

P.S. I'm not aware of any other tooltip plugin that has the same behavior.

Last edited 4 years ago by DysprosiumDy (previous) (diff)

comment:3 in reply to:  2 Changed 4 years ago by Scott González

Replying to DysprosiumDy:

Hey Scott,

How is this not a bug? What is the purpose of having a copy of the entire contents of the tooltip in the DOM until the tooltip is destroyed? In a web app that is built to stay open for a very long time, the useless divs pile up to absurd quantities. Now, if there's a particular purpose for this behavior, then I'd love to hear what it is.

Just look at the source, it's documented pretty clearly: https://github.com/jquery/jquery-ui/blob/20a636844961a1fb2de7a892ab28890091822e6a/ui/tooltip.js#L270

We have a tooltip that's a table with some information, styled. We have tooltips like that scattered all over the page. Each time a tooltip is hovered, even if just for split second, causes a complete copy of that table to be inserted into the DOM. Over time, this can build up to silly memory usage.

Unfortunately, there's nothing we can do about this right now. Accessibility is more important here.

But yeah. Can you explain what the purpose of this behavior is? It was introduced in a recent version of jQuery UI (I suspect 1.11) and it's big enough for me to have to regress to a previous version.

It makes the content accessible in the only way that we can find to work across multiple assistive technologies.

Kind regards, Dys

P.S. I'm not aware of any other tooltip plugin that has the same behavior.

Of course, because most developers completely ignore accessibility.

comment:4 Changed 4 years ago by DysprosiumDy

Thank you for your answers. They are much appreciated. I understand the reasoning behind this design now (and I feel your pain for having to do it this way), but the fact remains that this implementation is less than desirable. It's not the expected behavior for end users and it's not documented outside the source code.

This behavior is also applied to delegated tooltips, which makes the problem worse, because delegated tooltips are rarely destroyed. There has also never been a reason to do so. I've taken the liberty to look at some code on other websites I've worked on and see the same problem. Pages that don't reload (particularly web apps) create quite big memory leaks all around. This problem did not occur in older versions of jQuery UI. It's bad enough that we'd rather regress to an older version to prevent this issue... and we'd really like to keep all our projects up to date with the latest versions of jQuery / jQuery UI.

I do understand that accessibility is important, but in all the cases I've observed in our personal projects, it didn't matter. None of these tooltips are meant to be read aloud. They are however meant to be shown incredibly often on a page that doesn't reload. Gaining accessibility in favor of a memory leak seems like a bad tradeoff. Perhaps we could look for a way to allow for both? Maybe through an option?

I really hope this issue can be addressed in future updates. I also hope we can both agree that this behavior is less than desirable at least. Marking it as "not a bug" is one thing, but maybe it could still be marked as "bad side-effect"?

comment:5 in reply to:  4 Changed 4 years ago by Scott González

Resolution: notabug
Status: closedreopened

Replying to DysprosiumDy:

Thank you for your answers. They are much appreciated. I understand the reasoning behind this design now (and I feel your pain for having to do it this way), but the fact remains that this implementation is less than desirable. It's not the expected behavior for end users and it's not documented outside the source code.

Yeah, it's really unfortunate that accessibility usually comes at the cost of hacks and mangled code.

I do understand that accessibility is important, but in all the cases I've observed in our personal projects, it didn't matter. None of these tooltips are meant to be read aloud. They are however meant to be shown incredibly often on a page that doesn't reload. Gaining accessibility in favor of a memory leak seems like a bad tradeoff. Perhaps we could look for a way to allow for both? Maybe through an option?

We will never add an option to disable accessibility. Perhaps we can dynamically create and destroy the entire live region based on a timer after all tooltips are closed.

I really hope this issue can be addressed in future updates. I also hope we can both agree that this behavior is less than desirable at least. Marking it as "not a bug" is one thing, but maybe it could still be marked as "bad side-effect"?

I'll re-open to see if the dynamic creation will work. Hopefully completely removing the element will address the JAWS problem.

comment:6 Changed 4 years ago by Scott González

Status: reopenedopen

comment:7 Changed 4 years ago by DysprosiumDy

Thank you very much!

comment:8 Changed 4 years ago by tlhackque

I've seen this too. It's quite painful:

I have a dense menu with a lot of controls - each with a tooltip, and if you move the mouse over the menu, tooltips go up and down quite frequently, causing a lot of these hidden divs to be created.

I work in accessibility, so I'm not against it :-) But this behavior really isn't helpful in the sense that one mouse movement is giving a log that has the same data repeated 10s of times.

Suggestion: Set a timer and only make a log entry when a tooltip stays up for some reasonable minimum time - say a second or two. That would keep the log, but reduce the noise. (Note that virtual mice can move more slowly than real ones.)

Suggestion: Number the log entries. If making an entry that is within a reasonable window of another copy of the same text, enter something like "Dup of #10" instead.

In both cases, note that bandwidth to the user is also a precious resource - voice and Braille are both slower than optical reading. So avoiding thrash and collapsing duplicates is a good thing.

comment:9 Changed 4 years ago by tonkajuris

My team found this problem while working on production site today. Worried I might have to abandon current release version.

comment:10 Changed 4 years ago by tonkajuris

I ran into this today, very unfortunate.

comment:11 Changed 4 years ago by Nicksoft

I did found the resolution. We can utilize "close" option of tooltip. the trick is on close option call function and use destroy method as shown below. so above fiddler example can be resolved like below.

$(document).tooltip(close: function () {$(document).tooltip('destroy'); });

comment:12 Changed 3 years ago by Scott González

#14385 is a duplicate of this ticket.

comment:13 Changed 3 years ago by integritydc

Created a quick hack to preserve accessibility but keep the list of created elements under control:

http://jsfiddle.net/vszujhjt/

It cleans up the created elements, but leaves the most recently created one for accessibility's sake.

comment:14 Changed 2 years ago by D. Sidiropoulos

Credit goes to integritydc for his workaround. I made some adjustments to have it work with delegated tooltips:

        $("#filters").tooltip({
            items: ".some-class-here",

            close: function () { $(".ui-helper-hidden-accessible > *:not(:last)").remove(); },
        });
Last edited 2 years ago by Ryan J Ollos (previous) (diff)

comment:15 Changed 14 months ago by Michael N. Lipp

I've added the workaround to my code, works nicely. What I'd still like to know is whether this is going to be fixed in 1.12.2 (or 1.13), i.e. whether the cleanup will become a "built-in" part of the close functionality.

Should I make note of removing the workaround (that I'm spreading in my code now) when upgrading?

Note: See TracTickets for help on using tickets.