0

I'm putting together an application using Qt 5.12 where users will load JS scripts that interact with the app through its API. These scripts are bundled into "projects" (i.e multiple JS modules that depend on each other), and at any time I want only one project to be loaded into the JS engine, so if the user loads a different project, I want the previous context to be cleaned up.

Based on the documentation, I assumed that if I just delete the QJSEngine object and create a new one, this will allow me to create a fresh JS context.

QJSEngine* jsEngine = new QJSEngine();

// Load JS modules and run code...

jsEngine->collectGarbage();
delete jsEngine;

jsEngine = new QJSEngine();

// Load new JS modules...

When I try to run this code, I get an access violation exception at delete jsEngine. This is really strange, because the documentation itself states

Garbage is not collected from the persistent JS heap during QJSEngine destruction. If you need all memory freed, call collectGarbage manually right before destroying the QJSEngine.

which to me implied that I should be able to do this. Anyone have any ideas? Thanks in advance!

yah_nosh
  • 155
  • 1
  • 8
  • I even tried using `deleteLater`, or making the main window the parent of each QJSEngine I create (and thus have them cleaned up when the app is closed), but the problems persist. For some reason, the moment I have more than one instance of it, or if I try to delete an instance at any other time than when the app closes, I get some kind of memory access error. – yah_nosh Apr 13 '19 at 12:25

2 Answers2

2

Okay, so it turns out I'm a dummy and forgot to include one important detail: my application also exposes my "JavaScript interface" object to the JS engine using QJSEngine::newQObject, so I was pretty much just recreating this issue.

The solution is exactly the same: using QQmlEngine::setObjectOwnership makes the problem go away.

yah_nosh
  • 155
  • 1
  • 8
0

Make sure you don't have any remaining QJSValues lying around.

Alternatively, if you just want the state cleaned up. Clear the QJSEngine::globalObject(), or just avoid using the root JS state so nothing leaks between projects.

Allan Jensen
  • 518
  • 4
  • 8
  • Okay, I just found out what the source of my problem was: I expose my "interface" class using `newQObject` to the JS global object (I have the object give a pointer to itself when calling the function), and this causes the crash when I try deleting QJSEngine. But now do I "clean it up" before deleting? I tried using "deleteProperty" on the global object, but that did not work. – yah_nosh Apr 25 '19 at 21:55
  • Good question. I would assume somehow you need to stop referencing it, and then activate garbage collection. Note there are also different ownership models for bridged objects (either C++ or JS controlled if I remember correctly) – Allan Jensen Apr 26 '19 at 11:41
  • See answer above. Turns out there is a direct solution, but getting to it is rather unintuitive. Thanks for your comments though, they did help direct me toward the correct answer. – yah_nosh Apr 27 '19 at 11:12