diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index e7d638afa0..a856f0c1a8 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -27,7 +27,8 @@
 #include "ScriptException.h"
 
 // These are used for debugging memory leaks caused by persistent handles
-#define OVERTE_V8_HANDLE_COUNTERS
+// V8TODO: Rename to something better, like for example OVERTE_V8_MEMORY_DEBUG
+#define OVERTE_V8_MEMORY_DEBUG
 
 class QByteArray;
 class QLatin1String;
@@ -56,7 +57,7 @@ public:
     size_t totalAvailableSize;
     size_t totalGlobalHandlesSize;
     size_t usedGlobalHandlesSize;
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
     size_t scriptValueCount;
     size_t scriptValueProxyCount;
 #endif
@@ -399,6 +400,16 @@ public:
      */
     virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() = 0;
 
+    /**
+     * @brief Start collecting object statistics that can later be reported with dumpHeapObjectStatistics().
+     */
+    virtual void startCollectingObjectStatistics() = 0;
+
+    /**
+     * @brief Prints heap statistics to a file. Collecting needs to first be started with dumpHeapObjectStatistics().
+     */
+    virtual void dumpHeapObjectStatistics() = 0;
+
 public:
     // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
     bool IS_THREADSAFE_INVOCATION(const QString& method);
diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp
index a5b9ebb13b..5ce8a5666b 100644
--- a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp
+++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp
@@ -61,13 +61,21 @@ QVariantMap ScriptManagerScriptingInterface::getMemoryUsageStatistics() {
     map.insert("totalAvailableSize", QVariant((qulonglong)(statistics.totalAvailableSize)));
     map.insert("totalGlobalHandlesSize", QVariant((qulonglong)(statistics.totalGlobalHandlesSize)));
     map.insert("usedGlobalHandlesSize", QVariant((qulonglong)(statistics.usedGlobalHandlesSize)));
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
     map.insert("scriptValueCount", QVariant((qulonglong)(statistics.scriptValueCount)));
     map.insert("scriptValueProxyCount", QVariant((qulonglong)(statistics.scriptValueProxyCount)));
 #endif
     return map;
 }
 
+void ScriptManagerScriptingInterface::startCollectingObjectStatistics() {
+    _manager->engine()->startCollectingObjectStatistics();
+}
+
+void ScriptManagerScriptingInterface::dumpHeapObjectStatistics() {
+    _manager->engine()->dumpHeapObjectStatistics();
+}
+
 ScriptValue ScriptManagerScriptingInterface::createGarbageCollectorDebuggingObject() {
     //auto value = _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
     return _manager->engine()->newQObject(new TestQObject, ScriptEngine::ScriptOwnership);
diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h
index 8d37b2e7a3..2b9aeb49e8 100644
--- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h
+++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h
@@ -53,7 +53,7 @@
 class TestQObject : public QObject {
     Q_OBJECT
 public:
-    Q_INVOKABLE virtual void testMethod() { qDebug() << "TestQObject::testMethod"; };
+    //Q_INVOKABLE virtual void testMethod() { qDebug() << "TestQObject::testMethod"; };
 };
 
 class ScriptManagerScriptingInterface : public QObject {
@@ -510,6 +510,18 @@ public:
      */
     Q_INVOKABLE QVariantMap getMemoryUsageStatistics();
 
+    /**jsdoc
+     * Start collecting object statistics that can later be reported with Script.dumpHeapObjectStatistics().
+     * @function Script.dumpHeapObjectStatistics
+     */
+    Q_INVOKABLE void startCollectingObjectStatistics();
+
+    /**jsdoc
+     * Prints heap statistics to a file. Collecting needs to first be started with Script.dumpHeapObjectStatistics().
+     * @function Script.dumpHeapObjectStatistics
+     */
+    Q_INVOKABLE void dumpHeapObjectStatistics();
+
     /**jsdoc
      * Create test object for garbage collector debugging.
      * @function Script.createGarbageCollectorDebuggingObject()
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.cpp b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
index 07d8423a2a..ff8d96a707 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.cpp
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.cpp
@@ -42,6 +42,8 @@
 
 #include <Profile.h>
 
+#include <v8-profiler.h>
+
 #include "../ScriptEngineLogging.h"
 #include "../ScriptProgram.h"
 #include "../ScriptValue.h"
@@ -282,7 +284,11 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager *manager) : ScriptEngine(manager),
         // --assert-types
 
         v8::V8::InitializeICU();
-        v8::V8::SetFlagsFromString("--stack-size=256 --verify-heap --assert-types");
+#ifdef OVERTE_V8_MEMORY_DEBUG
+        v8::V8::SetFlagsFromString("--stack-size=256 --track_gc_object_stats --assert-types");
+#else
+        v8::V8::SetFlagsFromString("--stack-size=256");
+#endif
         //v8::V8::SetFlagsFromString("--stack-size=256 --single-threaded");
         v8::Platform* platform = getV8Platform();
         v8::V8::InitializePlatform(platform);
@@ -1720,10 +1726,31 @@ ScriptEngineMemoryStatistics ScriptEngineV8::getMemoryUsageStatistics() {
     statistics.totalAvailableSize = heapStatistics.total_available_size();
     statistics.totalGlobalHandlesSize = heapStatistics.total_global_handles_size();
     statistics.usedGlobalHandlesSize = heapStatistics.used_global_handles_size();
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
     statistics.scriptValueCount = scriptValueCount;
     statistics.scriptValueProxyCount = scriptValueProxyCount;
 #endif
-
     return statistics;
-}
\ No newline at end of file
+}
+
+void ScriptEngineV8::startCollectingObjectStatistics() {
+    auto heapProfiler = _v8Isolate->GetHeapProfiler();
+    heapProfiler->StartTrackingHeapObjects();
+}
+
+void ScriptEngineV8::dumpHeapObjectStatistics() {
+    // V8TODO: this is not very elegant, but very convenient
+    QFile dumpFile("/tmp/heap_objectStatistics_dump.csv");
+    if (!dumpFile.open(QFile::WriteOnly | QFile::Truncate)) {
+        return;
+    }
+    QTextStream dump(&dumpFile);
+    size_t objectTypeCount = _v8Isolate->NumberOfTrackedHeapObjectTypes();
+    for (size_t i = 0; i < objectTypeCount; i++) {
+        v8::HeapObjectStatistics statistics;
+        if (_v8Isolate->GetHeapObjectStatisticsAtLastGC(&statistics, i)) {
+            dump << statistics.object_type() << " " << statistics.object_sub_type() << " " << statistics.object_count() << " "
+                 << statistics.object_size() << "\n";
+        }
+    }
+}
diff --git a/libraries/script-engine/src/v8/ScriptEngineV8.h b/libraries/script-engine/src/v8/ScriptEngineV8.h
index c8bb460ef1..2ab8491d03 100644
--- a/libraries/script-engine/src/v8/ScriptEngineV8.h
+++ b/libraries/script-engine/src/v8/ScriptEngineV8.h
@@ -136,6 +136,8 @@ public:  // ScriptEngine implementation
     QString scriptValueDebugListMembersV8(const V8ScriptValue &v8Value);
     virtual void logBacktrace(const QString &title = QString("")) override;
     virtual ScriptEngineMemoryStatistics getMemoryUsageStatistics() override;
+    virtual void startCollectingObjectStatistics() override;
+    virtual void dumpHeapObjectStatistics() override;
 
     // helper to detect and log warnings when other code invokes QScriptEngine/BaseScriptEngine in thread-unsafe ways
     inline bool IS_THREADSAFE_INVOCATION(const QString& method) { return ScriptEngine::IS_THREADSAFE_INVOCATION(method); }
@@ -205,7 +207,7 @@ public: // not for public use, but I don't like how Qt strings this along with p
     void popContext();
     // V8TODO: call this after initializing global object
     void storeGlobalObjectContents();
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
     void incrementScriptValueCounter() { scriptValueCount++; };
     void decrementScriptValueCounter() { scriptValueCount--; };
     void incrementScriptValueProxyCounter() { scriptValueProxyCount++; };
@@ -264,7 +266,7 @@ protected:
     //ArrayBufferClass* _arrayBufferClass;
     // Counts how many nested evaluate calls are there at a given point
     int _evaluatingCounter;
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
     std::atomic<size_t> scriptValueCount{0};
     std::atomic<size_t> scriptValueProxyCount{0};
 #endif
diff --git a/libraries/script-engine/src/v8/V8Types.h b/libraries/script-engine/src/v8/V8Types.h
index fc67e45691..2c52175c9d 100644
--- a/libraries/script-engine/src/v8/V8Types.h
+++ b/libraries/script-engine/src/v8/V8Types.h
@@ -47,7 +47,7 @@ public:
             return;
         }
         Q_ASSERT(false);*/
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
         _engine->incrementScriptValueCounter();
 #endif
         _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), value));
@@ -70,7 +70,7 @@ public:
         v8::HandleScope handleScope(_engine->getIsolate());
         v8::Context::Scope(_engine->getContext());
         //_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
         _engine->incrementScriptValueCounter();
 #endif
         _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), v8::Local<T>()));
@@ -82,7 +82,7 @@ public:
         v8::HandleScope handleScope(_engine->getIsolate());
         v8::Context::Scope(_engine->getContext());
         //_value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
         _engine->incrementScriptValueCounter();
 #endif
         _value.reset(new v8::UniquePersistent<T>(_engine->getIsolate(), copied.constGet()));
@@ -136,7 +136,7 @@ public:
         v8::Isolate::Scope isolateScope(_engine->getIsolate());
         v8::HandleScope handleScope(_engine->getIsolate());
         //v8::Context::Scope(_engine->getContext());
-#ifdef OVERTE_V8_HANDLE_COUNTERS
+#ifdef OVERTE_V8_MEMORY_DEBUG
         _engine->decrementScriptValueCounter();
 #endif
         _value->Reset();