// Reset the nursery
resetNurseries();
- // start any pending finalizers
- RELEASE_SM_LOCK;
- scheduleFinalizers(cap, old_weak_ptr_list);
- ACQUIRE_SM_LOCK;
-
// send exceptions to any threads which were about to die
RELEASE_SM_LOCK;
resurrectThreads(resurrected_threads);
// Update the stable pointer hash table.
updateStablePtrTable(major_gc);
+ // unlock the StablePtr table. Must be before scheduleFinalizers(),
+ // because a finalizer may call hs_free_fun_ptr() or
+ // hs_free_stable_ptr(), both of which access the StablePtr table.
+ stablePtrPostGC();
+
+ // Start any pending finalizers. Must be after
+ // updateStablePtrTable() and stablePtrPostGC() (see #4221).
+ RELEASE_SM_LOCK;
+ scheduleFinalizers(cap, old_weak_ptr_list);
+ ACQUIRE_SM_LOCK;
+
+ if (major_gc) {
+ nat need, got;
+ need = BLOCKS_TO_MBLOCKS(n_alloc_blocks);
+ got = mblocks_allocated;
+ /* If the amount of data remains constant, next major GC we'll
+ require (F+1)*need. We leave (F+2)*need in order to reduce
+ repeated deallocation and reallocation. */
+ need = (RtsFlags.GcFlags.oldGenFactor + 2) * need;
+ if (got > need) {
+ returnMemoryToOS(got - need);
+ }
+ }
+
// check sanity after GC
IF_DEBUG(sanity, checkSanity(rtsTrue));
slop = calcLiveBlocks() * BLOCK_SIZE_W - live;
stat_endGC(allocated, live, copied, N, max_copied, avg_copied, slop);
- // unlock the StablePtr table
- stablePtrPostGC();
-
// Guess which generation we'll collect *next* time
initialise_N(force_major_gc);
void
waitForGcThreads (Capability *cap USED_IF_THREADS)
{
- nat n_threads = RtsFlags.ParFlags.nNodes;
- nat me = cap->no;
+ const nat n_threads = RtsFlags.ParFlags.nNodes;
+ const nat me = cap->no;
nat i, j;
rtsBool retry = rtsTrue;
void
releaseGCThreads (Capability *cap USED_IF_THREADS)
{
- nat n_threads = RtsFlags.ParFlags.nNodes;
- nat me = cap->no;
+ const nat n_threads = RtsFlags.ParFlags.nNodes;
+ const nat me = cap->no;
nat i;
for (i=0; i < n_threads; i++) {
if (i == me) continue;
if (!(bd->flags & BF_FRAGMENTED)) {
bd->flags |= BF_MARKED;
}
+
+ // BF_SWEPT should be marked only for blocks that are being
+ // collected in sweep()
+ bd->flags &= ~BF_SWEPT;
}
}
}
if (major_gc && RtsFlags.GcFlags.generations > 1) {
nat live, size, min_alloc, words;
- nat max = RtsFlags.GcFlags.maxHeapSize;
- nat gens = RtsFlags.GcFlags.generations;
+ const nat max = RtsFlags.GcFlags.maxHeapSize;
+ const nat gens = RtsFlags.GcFlags.generations;
// live in the oldest generations
if (oldest_gen->live_estimate != 0) {
// Auto-enable compaction when the residency reaches a
// certain percentage of the maximum heap size (default: 30%).
- if (RtsFlags.GcFlags.generations > 1 &&
- (RtsFlags.GcFlags.compact ||
- (max > 0 &&
- oldest_gen->n_blocks >
- (RtsFlags.GcFlags.compactThreshold * max) / 100))) {
+ if (RtsFlags.GcFlags.compact ||
+ (max > 0 &&
+ oldest_gen->n_blocks >
+ (RtsFlags.GcFlags.compactThreshold * max) / 100)) {
oldest_gen->mark = 1;
oldest_gen->compact = 1;
// debugBelch("compaction: on\n", live);
static void
resize_nursery (void)
{
- lnat min_nursery = RtsFlags.GcFlags.minAllocAreaSize * n_capabilities;
+ const lnat min_nursery = RtsFlags.GcFlags.minAllocAreaSize * n_capabilities;
if (RtsFlags.GcFlags.generations == 1)
{ // Two-space collector:
if (RtsFlags.GcFlags.heapSizeSuggestion)
{
long blocks;
- nat needed = calcNeeded(); // approx blocks needed at next GC
+ const nat needed = calcNeeded(); // approx blocks needed at next GC
/* Guess how much will be live in generation 0 step 0 next time.
* A good approximation is obtained by finding the