Fix memory leak, improve memory logging. (#2469)

This commit is contained in:
Nikolay Igotti
2018-12-18 14:13:23 +03:00
committed by GitHub
parent e720844ff6
commit b7d5452c1d
+49 -17
View File
@@ -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);
} }
} }