JDK-8123125 : WebView keeps permanent back buffers for HTML pages and Canvas objects, can cause NPE
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-09-11
  • Updated: 2015-06-17
  • Resolved: 2013-11-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8Fixed
Related Reports
Blocks :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Running the "FullTutorial" CanvasTest toy from rt-closed, we run out of texture resources trying to view all of the tabs due to an excessive number of textures marked "permanent" from the WebView code.

When we run out the statistics are printed out showing a full 256MB of textures allocated, 118 of which are marked permanent.  If I add a printStackTrace() in the "makePermanent()" method call I see that every object created in the WCBufferedContext/RTImage path is made permanent and never disposed.

The permanent flag should only be used sparingly for textures that contain data that cannot be reconstructed and which survives a given rendering pass (i.e. if it is only used within a single rendering pass and then the data becomes uninteresting, then a texture lock() operation should be used instead.  If the data needs to remain between rendering passes and cannot be constructed, then a call to makePermanent() can be made as a last resort).

It looks like these resources are created to manage save/restore operations, but I can't find any place where the state objects are disposed after use.
Comments
Verified on 8.0b120 running FullTutorial
31-12-2013

Fix pushed: changeset: 5777:2f3d579c8175 user: lepopov date: Thu Nov 21 20:14:23 2013 +0400 files: modules/web/src/main/java/com/sun/javafx/webkit/prism/WCPageBackBufferImpl.java description: Fixed RT-32845 WebView keeps permanent back buffer for HTML pages and Canvas objects, can cause NPE (Fix by Jim Graham; tested by Peter Zhelezniakov)
21-11-2013

Yes.
21-11-2013

Peter Z ��� release that sucker!! (ensure the Leonid Popov is aware of the change. Leonid?)
21-11-2013

Would be great to get this in today so we can test some of the other bugs that this may be affecting.
21-11-2013

I've tested Jim's patch for a couple of days and it seems to work well. In particular I've checked that when the backbuffer loses its texture a new one is created and the page is rendered properly. I've only made a few formatting changes to the patch. Review: http://cr.openjdk.java.net/~peterz/RT-32845/0/
21-11-2013

Looks good to me...
21-11-2013

I mentioned above that I had seen images disappearing when I originally tried that patch myself, but since then I've noticed that they sometimes don't appear even without that patch so that problem is most likely unrelated to the patch. If I had a reproducible set of circumstances I would submit a Jira issue for it, but it is really random and comes around rarely and then disappears for a long time and I can't reproduce it again... :(
20-11-2013

I'm testing Jim's patch and so far have found no problems.
20-11-2013

I've already posted a patch above...
18-11-2013

This one is cause failure after failure in WebView. Jim, please work with Peter and others on WebView so that this can be resolved.
18-11-2013

Permanent is not used for "needed from one rendering cycle to another". It is used for "I have absolutely no way to get this information back and the program will be forever broken if you free this buffer". The way you indicate that a texture is needed from one rendering cycle to another is to not manually dispose() it. We don't make a habit of disposing textures, it is unlikely to happen between 2 rendering cycles unless we are really, really short on memory. We have several mechanisms to keep your texture safe. In particular: - we only free them when we are running out of our vram allotment - we have an age indicator so that we can target textures that haven't been used recently first - we target textures that are not marked "contentsUseful()" before the ones that are marked (the webview backbuffer is marked useful as you can see in the code sample above) - we never, ever, get rid of permanent textures - those must be manually disposed() (or if their references are dropped then the Disposer can dispose() them, but not the code that is simply pruning texture memory) Note that node caches are not permanent, they are locked and unlocked and tagged with "contentsUseful()" instead. Those are an example of a scrolling/animation optimization as well. The reason the Canvas backbuffer is marked permanent is that we have absolutely no way to reconstruct it since the commands used to render it were lost after we ran them. We plan to eventually introduce API for developers to listen for texture-loss events and repair them, but until we have such an API, we mark them permanent. The WebView back buffer can be reconstructed (as far as I can tell) and its retention from frame to frame is only a performance optimization. It should be relying on the extensive support we have to protect such buffers, as do the node caches, shape mask caches, and image textures - by not marking them permanent...
14-11-2013

Excessive locking was fixed as part of RT-33625. As for page backbuffers, they are mostly needed for fast scrolling. So they are permanent by nature, in the sense that they can survive any number of rendering cycles. It's true they can be recreated at any time (it just takes long), so we might be able to drop a buffer if absolutely needed. But that should happen only occasionally, when it is certain that the dropped buffer wouldn't be recreated on the next rendering pass, e.g. when a WebView is being removed from the scene.
14-11-2013

Peter: is there anything more you need from Jim before you are able to fix this?
30-10-2013

Counting the canvases that should be created: There are 42 examples - which should create 42 webview back buffers. 41 of those have a single example and so those should create 41 FX Canvas objects + 41 Webview Canvas objects = 82 more. The remaining example has 11 sub-examples which should create 11 FX Canvas objects + 11 Webview Canvas objects = 22 more. 42 + 82 + 22 = 146 permanent buffers for the tutorial examples. Peter's analysis also showed 2 glyph caches, 2 gradient caches, an LCD buffer and a Region Image cache which is 6 more for the total of 152. I don't think there is much we can do for the Canvas buffers until we implement an option for FX applications to buy into "redraw requests". The question is whether or not there is anything we can do for the Webview buffers. Can any of those be recreated on demand with any amount of work? The HTML5 Canvas instances probably suffer from the same problem that the FX Canvas objects suffer, but what about the webview back buffers? Aren't those just renderings of HTML and can thus be recreated? Contrary to my previous comment I am going to create a new bug on the missing unlock()s and leave this bug to deal with the permanent resources...
17-10-2013

Actually, the stats being dumped to the console is a problem. They are only dumped if there is an unlocked resource at the end of a rendering cycle as there are here. Note that I am on retina, so the resource consumption is 4 times what one sees on non-retina. I show 93Meg of resources used by the end of the tutorial when I use a non-retina resolution. It would need 360Meg of VRAM to complete the tutorial on retina. But, note that 14% of the resources are locked (not permanent, just locked and nobody unlocked them). Those resources represent a (preventable) permanent loss of texture space and the locks should be found and paired with an unlock. The stats being dumped to the console are the indication that this is going wrong (we really should have a statement on them that explains that the stats are being printed as an error warning - I'm going to address that soon...) Reassigning back to Peter to find where the missing unlocks are...
17-10-2013

I've reduced FullTutorial to one test case, Sec2_1_3_Operations.java. Here's what my debugging shows: By the time the first RTImage is created, there are 18 permanent resources taking up 256M according to the stats printout. Of those resources: - two are created by GlyphCache ctor; - 11 are created by NGCanvas.initCanvas() -- which is reasonable, as the demo contains 11 canvases; - one contains WebView's back buffer; - one is created by BaseShaderContext.initLCDBuffer(); - one is created by RegionImageCache ctor; - two are created by PaintHelper.initGradientTextures(). Then 15 RTImages are created, of which 4 are later freed by calling RTImage.dispose(). The remaining 11 RTImages represent 11 HTML canvases. No permanent resources seem spent on short-lived objects.
24-09-2013

Other samples in FullTutorial have just one canvas. For each such sample in general, 3 permanent resources are created for FX canvas, HTML canvas, and WebView back buffer. Viewing all 40+ samples should therefore allocate about 150 permanent resources -- I get 152 in my testing on an MBP. Not sure how to proceed with this issue, so let me assign it back to Graphics. There are no functional problems due to this apparent lack of resources, just the stats constantly dumped to the console.
24-09-2013

Assign to Peter to triage.
11-09-2013