Crash on exit if CefApp.getInstance().dispose() called late

Having problems with building or using the JCEF Java binding? Ask your questions here.

Crash on exit if CefApp.getInstance().dispose() called late

Postby rkeen » Tue Jun 02, 2020 6:45 pm

In my application, I want to have multiple client/browser instances (e.g. for multiple windows that can be opened and closed during the application run). As such, I cannot call CefApp.getInstance().dispose() until after the windows containing the browser components have been closed and disposed. When the application exits, I call CefApp.getInstance().dispose() and wait for it to terminate fully before proceeding (state changes to CefAppState.TERMINATED). However, I when the application unloads, I get the following with a debug build
Code: Select all
[0602/192403.349:FATAL:browser_main.cc(217)] Check failed: global_request_context_->HasOneRef().

and a fatal error with a release build (I'm assuming due to the failed assert)
Code: Select all
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffd6c8946e6, pid=3712, tid=8680
#
# JRE version: OpenJDK Runtime Environment (11.0.6+10) (build 11.0.6+10)
# Java VM: OpenJDK 64-Bit Server VM (11.0.6+10, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [jcef.dll+0x346e6]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\...\hs_err_pid3712.log
#
# If you would like to submit a bug report, please visit:
#   https://github.com/AdoptOpenJDK/openjdk-support/issues
#


I can reproduce this in the simple test by reordering the calls to dispose() and CefApp.getInstance().dispose() in the WindowAdapter. When you call dispose() before CefApp.getInstance().dispose() you will see the same problem. This only seems to be an issue on Windows. Linux seems to work without error (or perhaps isn't reporting it).

Is there a recommended way to handle this? I've tried removing the browser UI component from the container and closing the browser, but neither seem to make a difference.
rkeen
Newbie
 
Posts: 5
Joined: Fri May 08, 2020 12:51 pm

Re: Crash on exit if CefApp.getInstance().dispose() called l

Postby Czarek » Tue Jun 02, 2020 7:38 pm

Are you releasing objects in OnBeforeClose? Keep a list of browsers and when the last one is being closed release app objects.
Maintainer of the CEF Python, PHP Desktop and CEF C API projects. My LinkedIn.
User avatar
Czarek
Virtuoso
 
Posts: 1927
Joined: Sun Nov 06, 2011 2:12 am

Re: Crash on exit if CefApp.getInstance().dispose() called l

Postby rkeen » Wed Jun 03, 2020 11:20 am

I could do that, but I don't want to dispose the app until my application is closing. I want to be able to use a browser, close its window and continue using my application with no browser, and then perhaps later open a new browser window. I won't know until my application is closing that a particular browser closing will be the last one used. Since you cannot use CefApp after it has been disposed, I can't really dispose it until I'm about to exit my application at which point the windows containing the browsers will have been closed.

I am nulling out my reference to the browser and client when removing it from the component hierarchy. Would it be better to keep a reference to the client and/or browser around until the app is ready to shut down? I thought it would be better to clean it up immediately to free up resources.
rkeen
Newbie
 
Posts: 5
Joined: Fri May 08, 2020 12:51 pm

Re: Crash on exit if CefApp.getInstance().dispose() called l

Postby Czarek » Wed Jun 03, 2020 1:14 pm

Here is your issue: https://github.com/chromiumembedded/cef ... in.cc#L222
Did you forget to release a CefBrowser reference?
This check may hit also if there are 0 references when you called Release too many times.
Maintainer of the CEF Python, PHP Desktop and CEF C API projects. My LinkedIn.
User avatar
Czarek
Virtuoso
 
Posts: 1927
Joined: Sun Nov 06, 2011 2:12 am

Re: Crash on exit if CefApp.getInstance().dispose() called l

Postby rkeen » Wed Jun 03, 2020 5:51 pm

In the simple example, there is a window listener:
Code: Select all
addWindowListener(new WindowAdapter() {

    @Override
    public void windowClosing(WindowEvent e) {

        CefApp.getInstance().dispose();
        dispose();
    }
});


Note that it first calls `CefApp.getInstance().dispose()` and then calls `dispose()` on the window. In my application, I cannot prevent the window from closing and being disposed and I cannot call `CefApp.getInstance().dispose()` before I am exiting my application because I may need to open new browser windows. I also don't want to keep a reference to browsers or clients around if they aren't going to be used again.

Note that I can reproduce the same issue in the simple test by simply reordering the calls so `dispose()` on the window happens before `CefApp.getInstance().dispose()`:

Code: Select all
addWindowListener(new WindowAdapter() {

    @Override
    public void windowClosing(WindowEvent e) {
        dispose();
        CefApp.getInstance().dispose();
    }
});


I don't see a place to call Release on a `CefBrowser` reference (the org.jcef.CefBrowser java wrapper). I have tried calling `dispose()` on the client (and also not calling it) when closing my window. I've also tried keeping a reference to the CefClient instance (which I assume keeps the references to the browsers it creates) for the duration of my application and even that doesn't work.

The only thing that does seem to work (at least no visible crash or error) is not calling `CefApp.getInstance().dispose()` when exiting, but that doesn't seem like a particularly good idea.

Any thoughts on how to handle releasing the references appropriately when calling `CefApp.getInstance().dispose()` after disposing the windows containing the client/browser reference? To be clear, I am using the JCEF Java wrapper classes, not the CEF C code directly, so unless there are hooks exposed there I won't have access to them.
rkeen
Newbie
 
Posts: 5
Joined: Fri May 08, 2020 12:51 pm

Re: Crash on exit if CefApp.getInstance().dispose() called l

Postby rkeen » Thu Jun 04, 2020 9:57 pm

It turns out that you need to call CefClient.dispose() before removing its browser components from their containers. Window.dispose() removes all the components which is why it was failing when I reordered the calls in windowClosing (CefApp.dispose() calls dispose() on any clients that haven't yet been disposed). Adding an override of removeNotify to my container solved the problem.

Code: Select all
@Override
protected void removeNotify() {
    getClient().dispose();
    super.removeNotify();
}
rkeen
Newbie
 
Posts: 5
Joined: Fri May 08, 2020 12:51 pm


Return to JCEF Forum

Who is online

Users browsing this forum: No registered users and 21 guests