Replace finalization queue with the linked list.
This commit is contained in:
committed by
Nikolay Igotti
parent
cedcd2cf79
commit
58a82b22bb
@@ -134,21 +134,6 @@ public:
|
|||||||
void incAlloc(size_t size, const ContainerHeader* header) {
|
void incAlloc(size_t size, const ContainerHeader* header) {
|
||||||
containerAllocs[toIndex(header)][0]++;
|
containerAllocs[toIndex(header)][0]++;
|
||||||
++(*allocationHistogram)[size];
|
++(*allocationHistogram)[size];
|
||||||
#if 0
|
|
||||||
auto queue = memoryState->finalizerQueue;
|
|
||||||
bool hit = false;
|
|
||||||
for (int i = 0; i < queue->size(); i++) {
|
|
||||||
auto container = (*queue)[i];
|
|
||||||
if (containerSize(container) == size) {
|
|
||||||
hit = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hit)
|
|
||||||
allocCacheHit++;
|
|
||||||
else
|
|
||||||
allocCacheMiss++;
|
|
||||||
#endif // USE_GC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void incFree(const ContainerHeader* header) {
|
void incFree(const ContainerHeader* header) {
|
||||||
@@ -230,9 +215,10 @@ struct MemoryState {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
// Finalizer queue.
|
// Finalizer queue - linked list of containers scheduled for finalization.
|
||||||
ContainerHeaderDeque* finalizerQueue;
|
ContainerHeader* finalizerQueue;
|
||||||
|
int finalizerQueueSize;
|
||||||
|
int finalizerQueueSuspendCount;
|
||||||
/*
|
/*
|
||||||
* Typical scenario for GC is as following:
|
* Typical scenario for GC is as following:
|
||||||
* we have 90% of objects with refcount = 0 which will be deleted during
|
* we have 90% of objects with refcount = 0 which will be deleted during
|
||||||
@@ -249,7 +235,6 @@ struct MemoryState {
|
|||||||
size_t gcThreshold;
|
size_t gcThreshold;
|
||||||
// If collection is in progress.
|
// If collection is in progress.
|
||||||
bool gcInProgress;
|
bool gcInProgress;
|
||||||
int finalizerQueueSuspendCount;
|
|
||||||
|
|
||||||
#if GC_ERGONOMICS
|
#if GC_ERGONOMICS
|
||||||
uint64_t lastGcTimestamp;
|
uint64_t lastGcTimestamp;
|
||||||
@@ -509,9 +494,10 @@ inline ContainerHeader* markAsRemoved(ContainerHeader* container) {
|
|||||||
|
|
||||||
inline void processFinalizerQueue(MemoryState* state) {
|
inline void processFinalizerQueue(MemoryState* state) {
|
||||||
// TODO: reuse elements of finalizer queue for new allocations.
|
// TODO: reuse elements of finalizer queue for new allocations.
|
||||||
while (!state->finalizerQueue->empty()) {
|
while (state->finalizerQueue != nullptr) {
|
||||||
auto container = memoryState->finalizerQueue->back();
|
auto* container = state->finalizerQueue;
|
||||||
state->finalizerQueue->pop_back();
|
state->finalizerQueue = container->nextLink();
|
||||||
|
state->finalizerQueueSize--;
|
||||||
#if TRACE_MEMORY
|
#if TRACE_MEMORY
|
||||||
state->containers->erase(container);
|
state->containers->erase(container);
|
||||||
#endif
|
#endif
|
||||||
@@ -519,15 +505,18 @@ inline void processFinalizerQueue(MemoryState* state) {
|
|||||||
konanFreeMemory(container);
|
konanFreeMemory(container);
|
||||||
atomicAdd(&allocCount, -1);
|
atomicAdd(&allocCount, -1);
|
||||||
}
|
}
|
||||||
|
RuntimeAssert(state->finalizerQueueSize == 0, "Queue must be empty here");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void scheduleDestroyContainer(
|
inline void scheduleDestroyContainer(MemoryState* state, ContainerHeader* container) {
|
||||||
MemoryState* state, ContainerHeader* container) {
|
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
state->finalizerQueue->push_front(container);
|
RuntimeAssert(container != nullptr, "Cannot destroy null container");
|
||||||
|
container->setNextLink(state->finalizerQueue);
|
||||||
|
state->finalizerQueue = container;
|
||||||
|
state->finalizerQueueSize++;
|
||||||
// We cannot clean finalizer queue while in GC.
|
// We cannot clean finalizer queue while in GC.
|
||||||
if (!state->gcInProgress && state->finalizerQueueSuspendCount == 0 && state->finalizerQueue->size() > 256) {
|
if (!state->gcInProgress && state->finalizerQueueSuspendCount == 0 && state->finalizerQueueSize > 256) {
|
||||||
processFinalizerQueue(state);
|
processFinalizerQueue(state);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -537,7 +526,6 @@ inline void scheduleDestroyContainer(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if !USE_GC
|
#if !USE_GC
|
||||||
|
|
||||||
template <bool Atomic>
|
template <bool Atomic>
|
||||||
@@ -1137,7 +1125,6 @@ MemoryState* InitMemory() {
|
|||||||
memoryState = konanConstructInstance<MemoryState>();
|
memoryState = konanConstructInstance<MemoryState>();
|
||||||
INIT_EVENT(memoryState)
|
INIT_EVENT(memoryState)
|
||||||
#if USE_GC
|
#if USE_GC
|
||||||
memoryState->finalizerQueue = konanConstructInstance<ContainerHeaderDeque>();
|
|
||||||
memoryState->toFree = konanConstructInstance<ContainerHeaderList>();
|
memoryState->toFree = konanConstructInstance<ContainerHeaderList>();
|
||||||
memoryState->roots = konanConstructInstance<ContainerHeaderList>();
|
memoryState->roots = konanConstructInstance<ContainerHeaderList>();
|
||||||
memoryState->gcInProgress = false;
|
memoryState->gcInProgress = false;
|
||||||
@@ -1155,8 +1142,8 @@ void DeinitMemory(MemoryState* memoryState) {
|
|||||||
konanDestructInstance(memoryState->toFree);
|
konanDestructInstance(memoryState->toFree);
|
||||||
konanDestructInstance(memoryState->roots);
|
konanDestructInstance(memoryState->roots);
|
||||||
|
|
||||||
konanDestructInstance(memoryState->finalizerQueue);
|
RuntimeAssert(memoryState->finalizerQueue == nullptr, "Finalizer queue must be empty");
|
||||||
memoryState->finalizerQueue = nullptr;
|
RuntimeAssert(memoryState->finalizerQueueSize == 0, "Finalizer queue must be empty");
|
||||||
|
|
||||||
#endif // USE_GC
|
#endif // USE_GC
|
||||||
|
|
||||||
|
|||||||
@@ -217,6 +217,15 @@ struct ContainerHeader {
|
|||||||
inline void resetSeen() {
|
inline void resetSeen() {
|
||||||
objectCount_ &= ~CONTAINER_TAG_GC_SEEN;
|
objectCount_ &= ~CONTAINER_TAG_GC_SEEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We cannot use 'this' here, as it conflicts with aliasing analysis in clang.
|
||||||
|
inline void setNextLink(ContainerHeader* next) {
|
||||||
|
*reinterpret_cast<ContainerHeader**>(this + 1) = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ContainerHeader* nextLink() {
|
||||||
|
return *reinterpret_cast<ContainerHeader**>(this + 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArrayHeader;
|
struct ArrayHeader;
|
||||||
|
|||||||
Reference in New Issue
Block a user