Fix memory leak, improve memory logging. (#2469)
This commit is contained in:
@@ -23,6 +23,7 @@
|
|||||||
#include "KAssert.h"
|
#include "KAssert.h"
|
||||||
#include "Atomic.h"
|
#include "Atomic.h"
|
||||||
#include "Exceptions.h"
|
#include "Exceptions.h"
|
||||||
|
#include "KString.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "MemoryPrivate.hpp"
|
#include "MemoryPrivate.hpp"
|
||||||
#include "Natives.h"
|
#include "Natives.h"
|
||||||
@@ -226,7 +227,7 @@ public:
|
|||||||
keys[index++] = it.first;
|
keys[index++] = it.first;
|
||||||
}
|
}
|
||||||
std::sort(keys.begin(), keys.end());
|
std::sort(keys.begin(), keys.end());
|
||||||
for (auto& it : keys) {
|
for (auto* it : keys) {
|
||||||
konan::consolePrintf(
|
konan::consolePrintf(
|
||||||
"%d bytes -> %d times\n", it, (*allocationHistogram)[it]);
|
"%d bytes -> %d times\n", it, (*allocationHistogram)[it]);
|
||||||
}
|
}
|
||||||
@@ -611,7 +612,7 @@ inline void DecrementRC(ContainerHeader* container) {
|
|||||||
} else if (UseCycleCollector) { // Possible root.
|
} else if (UseCycleCollector) { // Possible root.
|
||||||
RuntimeAssert(!Atomic, "Cycle collector shalln't be used with shared objects yet");
|
RuntimeAssert(!Atomic, "Cycle collector shalln't be used with shared objects yet");
|
||||||
RuntimeAssert(container->objectCount() == 1,
|
RuntimeAssert(container->objectCount() == 1,
|
||||||
"Cycle collector shall only work with single object containers");
|
"cycle collector shall only work with single object containers");
|
||||||
// We do not use cycle collector for frozen objects, as we already detected
|
// We do not use cycle collector for frozen objects, as we already detected
|
||||||
// possible cycles during freezing.
|
// possible cycles during freezing.
|
||||||
// Also do not use cycle collector for provable acyclic objects.
|
// Also do not use cycle collector for provable acyclic objects.
|
||||||
@@ -639,11 +640,47 @@ inline void initThreshold(MemoryState* state, uint32_t gcThreshold) {
|
|||||||
}
|
}
|
||||||
#endif // USE_GC
|
#endif // USE_GC
|
||||||
|
|
||||||
#if TRACE_MEMORY || USE_GC
|
#if TRACE_MEMORY && USE_GC
|
||||||
|
|
||||||
|
const char* colorNames[] = {"BLACK", "GRAY", "WHITE", "PURPLE", "GREEN", "ORANGE", "RED"};
|
||||||
|
|
||||||
|
void dumpObject(ObjHeader* ref, int indent) {
|
||||||
|
for (int i = 0; i < indent; i++) MEMORY_LOG(" ");
|
||||||
|
auto* typeInfo = ref->type_info();
|
||||||
|
auto* packageName =
|
||||||
|
typeInfo->packageName_ != nullptr ? CreateCStringFromString(typeInfo->packageName_) : nullptr;
|
||||||
|
auto* relativeName =
|
||||||
|
typeInfo->relativeName_ != nullptr ? CreateCStringFromString(typeInfo->relativeName_) : nullptr;
|
||||||
|
MEMORY_LOG("%p %s.%s\n", ref,
|
||||||
|
packageName ? packageName : "<unknown>", relativeName ? relativeName : "<unknown>");
|
||||||
|
if (packageName) konan::free(packageName);
|
||||||
|
if (relativeName) konan::free(relativeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpContainerContent(ContainerHeader* container) {
|
||||||
|
if (isAggregatingFrozenContainer(container)) {
|
||||||
|
MEMORY_LOG("%s aggregating container %p with %d objects rc=%d\n",
|
||||||
|
colorNames[container->color()], container, container->objectCount(), container->refCount());
|
||||||
|
ContainerHeader** subContainer = reinterpret_cast<ContainerHeader**>(container + 1);
|
||||||
|
for (int i = 0; i < container->objectCount(); ++i) {
|
||||||
|
ObjHeader* obj = reinterpret_cast<ObjHeader*>(subContainer + 1);
|
||||||
|
MEMORY_LOG(" object %p of type %p: ", obj, obj->type_info());
|
||||||
|
dumpObject(obj, 4);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MEMORY_LOG("%s regular %s%scontainer %p with %d objects rc=%d\n",
|
||||||
|
colorNames[container->color()],
|
||||||
|
container->frozen() ? "frozen " : "",
|
||||||
|
container->stack() ? "stack " : "",
|
||||||
|
container, container->objectCount(),
|
||||||
|
container->refCount());
|
||||||
|
ObjHeader* obj = reinterpret_cast<ObjHeader*>(container + 1);
|
||||||
|
dumpObject(obj, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet* seen) {
|
void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet* seen) {
|
||||||
MEMORY_LOG("%s: %p (%08x): %d refs\n", prefix, header, header->refCount_,
|
dumpContainerContent(header);
|
||||||
header->refCount_ >> CONTAINER_TAG_SHIFT)
|
|
||||||
seen->insert(header);
|
seen->insert(header);
|
||||||
traverseContainerReferredObjects(header, [prefix, seen](ObjHeader* ref) {
|
traverseContainerReferredObjects(header, [prefix, seen](ObjHeader* ref) {
|
||||||
auto* child = ref->container();
|
auto* child = ref->container();
|
||||||
@@ -656,10 +693,7 @@ void dumpWorker(const char* prefix, ContainerHeader* header, ContainerHeaderSet*
|
|||||||
|
|
||||||
void dumpReachable(const char* prefix, const ContainerHeaderSet* roots) {
|
void dumpReachable(const char* prefix, const ContainerHeaderSet* roots) {
|
||||||
ContainerHeaderSet seen;
|
ContainerHeaderSet seen;
|
||||||
for (auto container : *roots) {
|
for (auto* container : *roots) {
|
||||||
MEMORY_LOG("%p: %s%s\n", container,
|
|
||||||
container->frozen() ? "frozen " : "",
|
|
||||||
container->stack() ? "stack " : "")
|
|
||||||
dumpWorker(prefix, container, &seen);
|
dumpWorker(prefix, container, &seen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,10 +707,6 @@ void ScanRoots(MemoryState*);
|
|||||||
void CollectRoots(MemoryState*);
|
void CollectRoots(MemoryState*);
|
||||||
void Scan(ContainerHeader* container);
|
void Scan(ContainerHeader* container);
|
||||||
|
|
||||||
#if TRACE_MEMORY
|
|
||||||
const char* colorNames[] = {"BLACK", "GRAY", "WHITE", "PURPLE", "GREEN", "ORANGE", "RED"};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<bool useColor>
|
template<bool useColor>
|
||||||
void MarkGray(ContainerHeader* start) {
|
void MarkGray(ContainerHeader* start) {
|
||||||
ContainerHeaderDeque toVisit;
|
ContainerHeaderDeque toVisit;
|
||||||
@@ -699,8 +729,9 @@ void MarkGray(ContainerHeader* start) {
|
|||||||
if (container->marked()) continue;
|
if (container->marked()) continue;
|
||||||
container->mark();
|
container->mark();
|
||||||
}
|
}
|
||||||
|
|
||||||
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
|
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
|
||||||
auto childContainer = ref->container();
|
auto* childContainer = ref->container();
|
||||||
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
|
RuntimeAssert(!isArena(childContainer), "A reference to local object is encountered");
|
||||||
if (!Shareable(childContainer)) {
|
if (!Shareable(childContainer)) {
|
||||||
childContainer->decRefCount<false>();
|
childContainer->decRefCount<false>();
|
||||||
@@ -714,15 +745,16 @@ template<bool useColor>
|
|||||||
void ScanBlack(ContainerHeader* start) {
|
void ScanBlack(ContainerHeader* start) {
|
||||||
ContainerHeaderDeque toVisit;
|
ContainerHeaderDeque toVisit;
|
||||||
toVisit.push_front(start);
|
toVisit.push_front(start);
|
||||||
|
|
||||||
while (!toVisit.empty()) {
|
while (!toVisit.empty()) {
|
||||||
auto* container = toVisit.front();
|
auto* container = toVisit.front();
|
||||||
MEMORY_LOG("ScanBlack visit %p [%s]\n", container, colorNames[container->color()]);
|
MEMORY_LOG("ScanBlack visit %p [%s]\n", container, colorNames[container->color()]);
|
||||||
toVisit.pop_front();
|
toVisit.pop_front();
|
||||||
if (useColor) {
|
if (useColor) {
|
||||||
if (container->color() == CONTAINER_TAG_GC_GREEN) continue;
|
auto color = container->color();
|
||||||
|
if (color == CONTAINER_TAG_GC_GREEN || color == CONTAINER_TAG_GC_BLACK) continue;
|
||||||
container->setColorAssertIfGreen(CONTAINER_TAG_GC_BLACK);
|
container->setColorAssertIfGreen(CONTAINER_TAG_GC_BLACK);
|
||||||
} else {
|
} else {
|
||||||
|
if (container->marked()) continue;
|
||||||
container->unMark();
|
container->unMark();
|
||||||
}
|
}
|
||||||
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
|
traverseContainerReferredObjects(container, [&toVisit](ObjHeader* ref) {
|
||||||
@@ -775,7 +807,7 @@ void MarkRoots(MemoryState* state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ScanRoots(MemoryState* state) {
|
void ScanRoots(MemoryState* state) {
|
||||||
for (auto container : *(state->roots)) {
|
for (auto* container : *(state->roots)) {
|
||||||
Scan(container);
|
Scan(container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user