From 33bdd841c17edf19c626cc1989cd0f8a887ee075 Mon Sep 17 00:00:00 2001
From: ksuprynowicz <ksuprynowicz@post.pl>
Date: Mon, 30 Oct 2023 18:40:04 +0100
Subject: [PATCH] Fix entity server memory leak and improve performance

---
 libraries/entities/src/EntityTree.cpp | 10 ++--------
 libraries/entities/src/EntityTree.h   |  3 +++
 2 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp
index 5d23cf704b..f947f6707a 100644
--- a/libraries/entities/src/EntityTree.cpp
+++ b/libraries/entities/src/EntityTree.cpp
@@ -2553,9 +2553,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer
     }
     entityDescription["DataVersion"] = _persistDataVersion;
     entityDescription["Id"] = _persistID;
-    // V8TODO: Creating new script engine each time is very inefficient
-    ScriptEnginePointer engine = newScriptEngine();
-    RecurseOctreeToMapOperator theOperator(entityDescription, element, engine.get(), skipDefaultValues,
+    RecurseOctreeToMapOperator theOperator(entityDescription, element, scriptEngine.get(), skipDefaultValues,
                                             skipThoseWithBadParents, _myAvatar);
     withReadLock([&] {
         recurseTreeWithOperator(&theOperator);
@@ -2704,8 +2702,6 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
     // to a ScriptValue, and then to EntityItemProperties.  These properties are used
     // to add the new entity to the EntityTree.
     QVariantList entitiesQList = map["Entities"].toList();
-    // V8TODO: Creating new script engine each time is very inefficient
-    ScriptEnginePointer scriptEngine = newScriptEngine();
 
     if (entitiesQList.length() == 0) {
         qCDebug(entities) << "EntityTree::readFromMap: entitiesQList.length() == 0, Empty map or invalidly formed file";
@@ -2881,9 +2877,7 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) {
 }
 
 bool EntityTree::writeToJSON(QString& jsonString, const OctreeElementPointer& element) {
-    // V8TODO: Creating new script engine each time is very inefficient
-    ScriptEnginePointer engine = newScriptEngine();
-    RecurseOctreeToJSONOperator theOperator(element, engine.get(), jsonString);
+    RecurseOctreeToJSONOperator theOperator(element, scriptEngine.get(), jsonString);
     withReadLock([&] {
         recurseTreeWithOperator(&theOperator);
     });
diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h
index 78fab3af6f..5b7e5691c3 100644
--- a/libraries/entities/src/EntityTree.h
+++ b/libraries/entities/src/EntityTree.h
@@ -385,6 +385,9 @@ private:
     // Return an AACube containing object and all its entity descendants
     AACube updateEntityQueryAACubeWorker(SpatiallyNestablePointer object, EntityEditPacketSender* packetSender,
                                          MovingEntitiesOperator& moveOperator, bool force, bool tellServer);
+
+    // Script engine for writing entity tree data to and from JSON
+    ScriptEnginePointer scriptEngine{ newScriptEngine() };
 };
 
 void convertGrabUserDataToProperties(EntityItemProperties& properties);