Destructor of CefV8Handler is not called when there is no reference to the object.

Issue #3258 wontfix
Kohill Yang created an issue

To reproduce:

  1. Override the default destructor function of V8Handler in performace_test.cc, as the following says:
  __declspec(noinline) ~V8Handler() override {   
    volatile int i = 0;
    std::cerr << ";;;;;;;;;;;;;;;;;;;;;;" << i << std::endl;
  }

__declspec(noinline) can make sure the function is not inlined so we can add a breakpoint in this that.

  1. Start cefclient.exe.
  2. Navigate to the performance test page(http://tests/performance).
  3. Open Devtools.
  4. add a breakpoint in the destructor.
  5. run the following script in devtools:

delete window.GetPerfTests

delete window.RunPerfTest

delete window.PerfTestReturnValue

Now there is no object which holds a reference to the v8Handler, therefore, the destructor of the v8Handle should be called immediately, but it does not.

Comments (15)

  1. Marshall Greenblatt

    Now there is no object which holds a reference to the v8Handler, therefore, the destructor of the v8Handle should be called immediately, but it does not.

    You are making incorrect assumptions. Object release depends on the V8 GC and is not guaranteed to occur in any particular time frame.

  2. Kohill Yang reporter

    but it never called, even the program runs for several days, and even the memory is not enough. If that is really like what you have said, maybe there exist one bug in v8 GC.

  3. Kohill Yang reporter

    I proposed this issue because I have tried to assign some functions to an object using v8Handler several months ago. The v8 handler has allocated a big array. I assume that if there is no reference to the object and the big array will be freed once GC thinks it needs to do that. But the memory usage is increasing, as a result, OOM is reported.

  4. Marshall Greenblatt

    The v8 handler has allocated a big array. I assume that if there is no reference to the object and the big array will be freed once GC thinks it needs to do that. But the memory usage is increasing, as a result, OOM is reported.

    The GC doesn’t know the size of your native allocations. Consider using CefV8Value::CreateArrayBuffer instead, or implement your own solution to keep the allocation count/size reasonable.

  5. Marshall Greenblatt

    Restoring WontFix status for the same reasons stated above. Please do not change the status assigned to issues.

  6. Kohill Yang reporter

    The v8Handler’s destructor is called only when the context is destroyed. Even when I use  AdjustAmountOfExternalAllocatedMemory to tell v8 the external heap is hungry. I know GC is not guaranteed to collect the handler in a limited time, but the v8 handler should be collected once the full GC is done. I tried several ways to trigger the full GC, but none of them works. Considering the case that there exists a strong reference to the v8 handler, and the reference becomes weak only when the context is destroyed, then the v8 handler will be never collected.

    It should be OK if CEF thinks the v8 handler will only be destroyed after the context is released. In this case, it is not a bug, and should never be fixed.

  7. Marshall Greenblatt

    Considering the case that there exists a strong reference to the v8 handler, and the reference becomes weak only when the context is destroyed, then the v8 handler will be never collected.

    What is holding the strong reference?

    It should be OK if CEF thinks the v8 handler will only be destroyed after the context is released.

    As you say, everything should be released when the context is destroyed (at the latest). Further improvements to this behavior could be worth considering.

  8. Marshall Greenblatt

    Note that ArrayBuffers should be freed (CefV8ArrayBufferReleaseCallback called) when the object is no longer referenced, and shouldn’t be blocked currently on context destruction.

  9. Kohill Yang reporter

    Yes, and many thanks to the CEF. Our program largely relies on the feature of CefV8ArrayBufferReleaseCallback to share data between CPP and v8 world. With CefV8ArrayBufferReleaseCallback the images in CPP(over 2G per image) can be transferred to v8 without any copy, and once there is no reference to the image, it will be collected, this is very convenient. But recently we are facing a more difficult problem, we have to transfer a very complex data structure from CPP to javascript. And without using finalizer callback we have to create millions of v8 objects, which is very slow. So I’m looking for some ways to create such an object, it owns a pointer and once it is GC, the pointer will be deleted, and it has assigned a function to retrieve a part of the data, instead of creating the whole v8 object. I know there are many workarounds there, like using a global v8 handler and using a global function to retrieve the data part, but it would be a bit more inconvenient. The GUI programmer has to take care of the lifetime of the object, closing it once he thinks it should be closed, and not using it after the object is closed.

  10. Log in to comment