Skip to content

Commit

Permalink
fix memory leak (cocos#10804)
Browse files Browse the repository at this point in the history
  • Loading branch information
stanleyljl authored Apr 20, 2022
1 parent 3da31ad commit 3374c7e
Show file tree
Hide file tree
Showing 23 changed files with 214 additions and 68 deletions.
15 changes: 13 additions & 2 deletions native/cocos/application/ApplicationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ ApplicationManager *ApplicationManager::getInstance() {
return &mgr;
}

void ApplicationManager::closeAllApplications() {
for (auto &app : _apps) {
app->close();
}
}

void ApplicationManager::releseAllApplications() {
_apps.clear();
}
Expand All @@ -50,9 +56,14 @@ ApplicationManager::ApplicationPtr ApplicationManager::getCurrentAppSafe() const
}
} // namespace cc

//
void cocos_close() { // NOLINT(readability-identifier-naming)
// Called in the platform layer, because the platform layer is isolated from the application layer
// It is the platform layer to drive applications and reclaim resources.
cc::ApplicationManager::getInstance()->closeAllApplications();
}

void cocos_destory() { // NOLINT(readability-identifier-naming)
// Called in the platform layer, because the platform layer is isolated from the application layer
// It is the platform layer to drive applications and reclaim resources.
cc::ApplicationManager::getInstance()->releseAllApplications();
}
}
7 changes: 6 additions & 1 deletion native/cocos/application/ApplicationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ class CC_DLL ApplicationManager {
return app;
}

/**
* @brief close all generated applications before being destroyed.
*/
void closeAllApplications();

/**
* @brief Release all generated applications.
*/
Expand Down Expand Up @@ -87,6 +92,6 @@ class CC_DLL ApplicationManager {
} while (0)

#define CC_REGISTER_APPLICATION(className) \
int cocos_main(int argc, const char** argv) { \
int cocos_main(int argc, const char **argv) { \
CC_START_APPLICATION(className); \
}
2 changes: 1 addition & 1 deletion native/cocos/base/Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void Scheduler::removeHashElement(HashTimerEntry *element) {
element->timers.clear();

_hashForTimers.erase(element->target);
free(element);
delete element;
}
}

Expand Down
2 changes: 1 addition & 1 deletion native/cocos/base/memory/CallStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

namespace cc {

#define MAX_STACK_FRAMES 32
#define MAX_STACK_FRAMES 64
#define MAX_SYMBOL_LENGTH 255

/**
Expand Down
54 changes: 51 additions & 3 deletions native/cocos/base/memory/MemoryHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,34 @@ void MemoryHook::removeRecord(uint64_t address) {
_hooking = false;
}

static bool isIgnored(const StackFrame &frame) {
static const ccstd::vector<ccstd::string> ignoreModules = {
"SDL2",
"SogouPy"};

static const ccstd::vector<ccstd::string> ignoreFunctions = {
"eglGetProcAddress",
"eglWaitSync",
"gles3wOpen",
"gles2wOpen",
"type_info::name",
"DrvValidateVersion"};

for (auto &module : ignoreModules) {
if (frame.module.find(module) != ccstd::string::npos) {
return true;
}
}

for (auto &function : ignoreFunctions) {
if (frame.function.find(function) != ccstd::string::npos) {
return true;
}
}

return false;
}

void MemoryHook::dumpMemoryLeak() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
Expand All @@ -210,16 +238,34 @@ void MemoryHook::dumpMemoryLeak() {
log(stream.str());
}

int i = 0;
uint32_t i = 0;
size_t skipSize = 0;
uint32_t skipCount = 0;

for (const auto &iter : _records) {
bool skip = false;
auto frames = CallStack::backtraceSymbols(iter.second.callstack);
for (auto &frame : frames) {
if (isIgnored(frame)) {
skip = true;
break;
}
}

if (skip) {
skipSize += iter.second.size;
skipCount++;
continue;
}

std::stringstream stream;
int k = 0;

stream << std::endl;
stream << "<" << ++i << ">:"
<< "leak " << iter.second.size << " bytes at 0x" << std::hex << iter.second.address << std::dec << std::endl;
stream << "\tcallstack:" << std::endl;
auto frames = CallStack::backtraceSymbols(iter.second.callstack);

for (auto &frame : frames) {
stream << "\t[" << ++k << "]:" << frame.toString() << std::endl;
}
Expand All @@ -229,7 +275,9 @@ void MemoryHook::dumpMemoryLeak() {

std::stringstream endStream;
endStream << std::endl
<< "Total Leak: " << _totalSize << " bytes" << std::endl;
<< "Total leak count: " << _records.size() << " with " << _totalSize << " bytes, "
<< "Total skip count: " << skipCount << " with " << skipSize << " bytes" << std::endl;

endStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
endStream << "--------------------------------------memory leak report end---------------------------------------------" << std::endl;
endStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
Expand Down
6 changes: 3 additions & 3 deletions native/cocos/base/memory/MemoryHook.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ class CC_DLL MemoryHook {
*/
using RecordMap = ccstd::unordered_map<uint64_t, MemoryRecord>;

void addRecord(uint64_t address, size_t size);
void removeRecord(uint64_t address);
size_t getTotalSize() const { return _totalSize; }
void addRecord(uint64_t address, size_t size);
void removeRecord(uint64_t address);
inline size_t getTotalSize() const { return _totalSize; }

private:
/**
Expand Down
9 changes: 8 additions & 1 deletion native/cocos/bindings/jswrapper/v8/ScriptEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,14 @@ ScriptEngine::ScriptEngine()
#endif
}

ScriptEngine::~ScriptEngine() = default;
ScriptEngine::~ScriptEngine() {
#if !CC_EDITOR
if (gSharedV8) {
delete gSharedV8;
gSharedV8 = nullptr;
}
#endif
}

bool ScriptEngine::postInit() {
v8::HandleScope hs(_isolate);
Expand Down
18 changes: 12 additions & 6 deletions native/cocos/bindings/manual/jsb_global_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,26 +66,32 @@ static ccstd::string removeFileExt(const ccstd::string &filePath) {
return filePath;
}

static void walkCb(uv_handle_t *handle, void * /*arg*/) {
uv_close(handle, nullptr);
}

static int selectPort(int port) {
struct sockaddr_in addr;
static uv_tcp_t server;
uv_loop_t * loop = uv_loop_new();
int tryTimes = 200;
int startPort = port;
uv_loop_t loop;
uv_loop_init(&loop);
int tryTimes = 200;
int startPort = port;
while (tryTimes-- > 0) {
uv_tcp_init(loop, &server);
uv_tcp_init(&loop, &server);
uv_ip4_addr("0.0.0.0", startPort, &addr);
uv_tcp_bind(&server, reinterpret_cast<const struct sockaddr *>(&addr), 0);
int r = uv_listen(reinterpret_cast<uv_stream_t *>(&server), 5, nullptr);
uv_close(reinterpret_cast<uv_handle_t *>(&server), nullptr);
if (r) {
SE_LOGD("Failed to listen port %d, error: %s. Try next port\n", startPort, uv_strerror(r));
startPort += 1;
} else {
break;
}
}
uv_loop_close(loop);
uv_walk(&loop, walkCb, nullptr);
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
return startPort;
}

Expand Down
3 changes: 0 additions & 3 deletions native/cocos/core/Root.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,13 @@ Root::Root(gfx::Device *device)
_eventProcessor = new CallbacksInvoker();
// TODO(minggo):
// this._dataPoolMgr = legacyCC.internal.DataPoolManager && new legacyCC.internal.DataPoolManager(device) as DataPoolManager;
_cameraPool = new memop::Pool<scene::Camera>([this]() { return new scene::Camera(_device); },
4);

_cameraList.reserve(6);
_swapchains.reserve(2);
}

Root::~Root() {
instance = nullptr;
delete _cameraPool;
CC_SAFE_DELETE(_eventProcessor);
}

Expand Down
5 changes: 0 additions & 5 deletions native/cocos/core/geometry/Frustum.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,6 @@ class Frustum final : public ShapeBase {
void split(float start, float end, float aspect, float fov, const Mat4 &transform);
void updatePlanes();
void update(const Mat4 &m, const Mat4 &inv);
Frustum clone() const {
Frustum tmp;
copy(&tmp, *this);
return tmp;
}
};

} // namespace geometry
Expand Down
45 changes: 23 additions & 22 deletions native/cocos/engine/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
#if CC_USE_SOCKET
#include "cocos/network/WebSocket.h"
#endif
#if CC_USE_DRAGONBONES
#include "editor-support/dragonbones-creator-support/ArmatureCacheMgr.h"
#endif
#if CC_USE_SPINE
#include "editor-support/spine-creator-support/SkeletonCacheMgr.h"
#endif

#include "application/ApplicationManager.h"
#include "application/BaseApplication.h"
Expand Down Expand Up @@ -100,22 +106,28 @@ Engine::~Engine() {
AudioEngine::end();
#endif

Root::getInstance()->getPipeline()->destroy();
#if CC_USE_DRAGONBONES
dragonBones::ArmatureCacheMgr::destroyInstance();
#endif

#if CC_USE_SPINE
spine::SkeletonCacheMgr::destroyInstance();
#endif
network::HttpClient::destroyInstance();
EventDispatcher::destroy();
se::ScriptEngine::destroyInstance();
ProgramLib::destroyInstance();
BuiltinResMgr::destroyInstance();
gfx::DeviceManager::destroy();

CCObject::deferredDestroy();

BasePlatform *platform = BasePlatform::getPlatform();
platform->setHandleEventCallback(nullptr);

Root::getInstance()->getPipeline()->destroy();
CC_PROFILER_DESTROY;
DebugRenderer::destroyInstance();
FreeTypeFontFace::destroyFreeType();
cc::EventDispatcher::destroy();
FileUtils::destroyInstance();

se::ScriptEngine::getInstance()->cleanup();
se::ScriptEngine::destroyInstance();
gfx::DeviceManager::destroy();
CCObject::deferredDestroy();
}

int32_t Engine::init() {
Expand Down Expand Up @@ -154,29 +166,18 @@ int Engine::restart() {
}

void Engine::close() { // NOLINT
if (cc::EventDispatcher::initialized()) {
cc::EventDispatcher::dispatchCloseEvent();
}

auto *scriptEngine = se::ScriptEngine::getInstance();

cc::DeferredReleasePool::clear();
#if CC_USE_AUDIO
cc::AudioEngine::stopAll();
#endif
//#if CC_USE_SOCKET
// cc::network::WebSocket::closeAllConnections();
//#endif
cc::network::HttpClient::destroyInstance();

_scheduler->removeAllFunctionsToBePerformedInCocosThread();
_scheduler->unscheduleAll();

scriptEngine->cleanup();
cc::EventDispatcher::destroy();

// exit
exit(0);
BasePlatform *platform = BasePlatform::getPlatform();
platform->setHandleEventCallback(nullptr);
}

uint Engine::getTotalFrames() const {
Expand Down
14 changes: 8 additions & 6 deletions native/cocos/platform/UniversalPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@

#include "platform/interfaces/OSInterface.h"

extern int cocos_main(int argc, const char** argv); // NOLINT(readability-identifier-naming)
extern int cocos_main(int argc, const char **argv); // NOLINT(readability-identifier-naming)
extern void cocos_close(); // NOLINT(readability-identifier-naming)
extern void cocos_destory(); // NOLINT(readability-identifier-naming)

namespace cc {
UniversalPlatform::OSType UniversalPlatform::getOSType() const {
return getInterface<ISystem>()->getOSType();
}

void UniversalPlatform::dispatchEvent(const OSEvent& ev) {
void UniversalPlatform::dispatchEvent(const OSEvent &ev) {
bool isHandled = false;
if (_handleEventCallback) {
isHandled = (_handleEventCallback)(ev);
Expand All @@ -51,10 +52,10 @@ void UniversalPlatform::dispatchEvent(const OSEvent& ev) {
}
}

void UniversalPlatform::dispatchTouchEvent(const OSEvent& ev) {
void UniversalPlatform::dispatchTouchEvent(const OSEvent &ev) {
}

void UniversalPlatform::handleDefaultEvent(const OSEvent& ev) {
void UniversalPlatform::handleDefaultEvent(const OSEvent &ev) {
// TODO(cc) : Follow-up support
}

Expand All @@ -66,7 +67,7 @@ void UniversalPlatform::setHandleDefaultEventCallback(HandleEventCallback cb) {
_handleDefaultEventCallback = cb;
}

int32_t UniversalPlatform::run(int argc, const char** argv) {
int32_t UniversalPlatform::run(int argc, const char **argv) {
if (cocos_main(argc, argv) != 0) {
return -1;
}
Expand All @@ -77,7 +78,7 @@ int UniversalPlatform::getSdkVersion() const {
return 0;
}

void UniversalPlatform::runInPlatformThread(const ThreadCallback& task) {
void UniversalPlatform::runInPlatformThread(const ThreadCallback &task) {
_mainTask = task;
}

Expand Down Expand Up @@ -105,6 +106,7 @@ void UniversalPlatform::onResume() {
}

void UniversalPlatform::onClose() {
cocos_close();
}

void UniversalPlatform::onDestory() {
Expand Down
Loading

0 comments on commit 3374c7e

Please sign in to comment.