Add memory tracking to additional container classes (#8392)

Only show in developer changelog
This commit is contained in:
Florian Rival
2026-03-16 11:44:23 +01:00
committed by GitHub
parent 14da034ff6
commit efa780179e
13 changed files with 87 additions and 9 deletions
+1 -1
View File
@@ -55,7 +55,7 @@ install:
script:
# GDCore tests:
- cd .build-tests
- Core/GDCore_tests
- for i in {1..20}; do echo "Run $i"; Core/GDCore_tests; done
- cd ..
# GDevelop.js tests
- cd GDevelop.js
+4
View File
@@ -11,6 +11,7 @@
#include "GDCore/Project/Behavior.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/Project/ObjectConfiguration.h"
#include "GDCore/Project/VariablesContainer.h"
#include "GDCore/String.h"
@@ -153,6 +154,9 @@ protected:
* behaviors and it must be a deep copy.
*/
void Init(const gd::BehaviorsContainer &behaviorsContainer);
private:
gd::MemoryTracked _memoryTracked{this, "BehaviorsContainer"};
};
} // namespace gd
+12
View File
@@ -8,6 +8,7 @@
#include "GDCore/String.h"
#include "GDCore/Project/BehaviorConfigurationContainer.h"
#include "GDCore/Project/MemoryTrackedRegistry.h"
namespace gd {
@@ -25,8 +26,19 @@ class GD_CORE_API BehaviorsSharedData: public BehaviorConfigurationContainer {
BehaviorsSharedData(): BehaviorConfigurationContainer() {};
BehaviorsSharedData(const gd::String& name_, const gd::String& type_)
: BehaviorConfigurationContainer(name_, type_) {};
BehaviorsSharedData(const BehaviorsSharedData& other)
: BehaviorConfigurationContainer(other) {};
BehaviorsSharedData& operator=(const BehaviorsSharedData& other) {
if (this != &other) {
BehaviorConfigurationContainer::operator=(other);
}
return *this;
}
virtual ~BehaviorsSharedData();
virtual BehaviorsSharedData* Clone() const { return new BehaviorsSharedData(*this); }
private:
gd::MemoryTracked _memoryTracked{this, "BehaviorsSharedData"};
};
} // namespace gd
+2
View File
@@ -9,6 +9,7 @@
#include <vector>
#include <algorithm>
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/String.h"
namespace gd {
@@ -119,6 +120,7 @@ class GD_CORE_API EffectsContainer {
std::vector<std::shared_ptr<gd::Effect>> effects;
static Effect badEffect;
void Init(const EffectsContainer& other);
gd::MemoryTracked _memoryTracked{this, "EffectsContainer"};
};
} // namespace gd
@@ -8,6 +8,7 @@
#include <list>
#include "GDCore/Project/InitialInstance.h"
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/String.h"
namespace gd {
class InitialInstanceFunctor;
@@ -38,6 +39,14 @@ namespace gd {
class GD_CORE_API InitialInstancesContainer {
public:
InitialInstancesContainer(){};
InitialInstancesContainer(const InitialInstancesContainer& other)
: initialInstances(other.initialInstances) {};
InitialInstancesContainer& operator=(const InitialInstancesContainer& other) {
if (this != &other) {
initialInstances = other.initialInstances;
}
return *this;
}
virtual ~InitialInstancesContainer();
/**
@@ -198,6 +207,7 @@ private:
std::list<gd::InitialInstance> initialInstances;
static gd::InitialInstance badPosition;
gd::MemoryTracked _memoryTracked{this, "InitialInstancesContainer"};
};
/**
+9
View File
@@ -9,6 +9,7 @@
#include <vector>
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/String.h"
namespace gd {
@@ -21,6 +22,13 @@ namespace gd {
class GD_CORE_API LayersContainer {
public:
LayersContainer();
LayersContainer(const LayersContainer& other) : layers(other.layers) {};
LayersContainer& operator=(const LayersContainer& other) {
if (this != &other) {
layers = other.layers;
}
return *this;
}
/**
* \brief Return true if the layer called "name" exists.
@@ -104,6 +112,7 @@ class GD_CORE_API LayersContainer {
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
///< find an appropriate layer.
std::vector<gd::Layer> layers; ///< Layers
gd::MemoryTracked _memoryTracked{this, "LayersContainer"};
};
} // namespace gd
+11 -2
View File
@@ -30,16 +30,19 @@ class MemoryTrackedRegistry {
public:
// Internal C++ API (used by MemoryTracked).
static void add(const void* ptr, const char* className) {
if (!className) return;
dead()[className].erase(ptr);
alive()[className].insert(ptr);
}
static void remove(const void* ptr, const char* className) {
if (!className) return;
alive()[className].erase(ptr);
dead()[className].insert(ptr);
}
static bool isDead(const void* ptr, const char* className) {
if (!className) return false;
auto it = dead().find(className);
return it != dead().end() && it->second.count(ptr) > 0;
}
@@ -116,15 +119,21 @@ class MemoryTrackedRegistry {
* MemoryTracked _memoryTracked{this, "Layout"};
* };
* \endcode
*
* When adding a new tracked class, also update:
* - GDevelop.js/Bindings/postjs.js (trackedClassNames set in
* patchClassesForUseAfterFreeDetection)
* - newIDE/app/src/MainFrame/MemoryTrackedRegistryDialog.js (trackedClasses
* array)
*/
class MemoryTracked {
public:
MemoryTracked(const void* owner, const char* className)
: owner_(owner), className_(className) {
MemoryTrackedRegistry::add(owner_, className_);
if (className_) MemoryTrackedRegistry::add(owner_, className_);
}
~MemoryTracked() { MemoryTrackedRegistry::remove(owner_, className_); }
~MemoryTracked() { if (className_) MemoryTrackedRegistry::remove(owner_, className_); }
// Non-copyable, non-movable.
MemoryTracked(const MemoryTracked&) = delete;
@@ -10,6 +10,7 @@
#include <memory>
#include <vector>
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/Project/ObjectGroup.h"
#include "GDCore/String.h"
namespace gd {
@@ -189,6 +190,7 @@ class GD_CORE_API ObjectGroupsContainer {
private:
std::vector<std::unique_ptr<gd::ObjectGroup>> objectGroups;
static ObjectGroup badGroup;
gd::MemoryTracked _memoryTracked{this, "ObjectGroupsContainer"};
};
} // namespace gd
+2
View File
@@ -8,6 +8,7 @@
#include <memory>
#include <vector>
#include <set>
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/String.h"
#include "GDCore/Project/ObjectGroupsContainer.h"
#include "GDCore/Project/ObjectFolderOrObject.h"
@@ -252,6 +253,7 @@ class GD_CORE_API ObjectsContainer {
private:
SourceType sourceType = Unknown;
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
gd::MemoryTracked _memoryTracked{this, "ObjectsContainer"};
/**
* Initialize from another variables container, copying elements. Used by
+2
View File
@@ -7,6 +7,7 @@
#pragma once
#include <memory>
#include <vector>
#include "GDCore/Project/MemoryTrackedRegistry.h"
#include "GDCore/Project/Variable.h"
#include "GDCore/String.h"
namespace gd {
@@ -195,6 +196,7 @@ class GD_CORE_API VariablesContainer {
///< useful for computing changesets.
static gd::Variable badVariable;
static gd::String badName;
gd::MemoryTracked _memoryTracked{this, "VariablesContainer"};
/**
* Initialize from another variables container, copying elements. Used by
+2 -2
View File
@@ -78,9 +78,9 @@ TEST_CASE("EventsList", "[common][events]") {
size_t endMemory = gd::SystemStats::GetUsedVirtualMemory();
INFO("Memory used: " << endMemory - startMemory << "KB");
#if defined(WINDOWS)
REQUIRE(3000 >= endMemory - startMemory);
REQUIRE(3800 >= endMemory - startMemory);
#else
REQUIRE(1650 >= endMemory - startMemory);
REQUIRE(2000 >= endMemory - startMemory);
#endif
}
}
+15 -2
View File
@@ -421,7 +421,20 @@ function patchClassesForUseAfterFreeDetection(
patchClassesForUseAfterFreeDetection(Module, {
skippedClassNames: new Set([]),
// If adding new classes, also add them to `MemoryTrackedRegistryDialog`.
trackedClassNames: new Set(['Project', 'Layout', 'gdObject', 'Behavior']),
// If adding new classes, also add them to `MemoryTrackedRegistryDialog`
// and to the MemoryTracked member in the C++ class header.
trackedClassNames: new Set([
'Project',
'Layout',
'gdObject',
'Behavior',
'BehaviorsSharedData',
'EffectsContainer',
'InitialInstancesContainer',
'LayersContainer',
'ObjectGroupsContainer',
'ObjectsContainer',
'VariablesContainer',
]),
verbose: false,
});
@@ -15,8 +15,21 @@ import {
const gd: libGDevelop = global.gd;
// If adding new classes, also add them to `patchClassesForUseAfterFreeDetection`.
const trackedClasses = ['Project', 'Layout', 'gdObject', 'Behavior'];
// If adding new classes, also add them to `patchClassesForUseAfterFreeDetection`
// in postjs.js and to the MemoryTracked member in the C++ class header.
const trackedClasses = [
'Project',
'Layout',
'gdObject',
'Behavior',
'BehaviorsSharedData',
'EffectsContainer',
'InitialInstancesContainer',
'LayersContainer',
'ObjectGroupsContainer',
'ObjectsContainer',
'VariablesContainer',
];
type Stats = {|
className: string,