@@ -2171,12 +2171,13 @@ struct Gcx
2171
2171
// log--;
2172
2172
}
2173
2173
2174
- // collection step 3: free all unreferenced objects
2174
+ // collection step 3: finalize unreferenced objects, recover full pages with no live objects
2175
2175
size_t sweep () nothrow
2176
2176
{
2177
2177
// Free up everything not marked
2178
2178
debug (COLLECT_PRINTF ) printf(" \t free'ing\n " );
2179
2179
size_t freedLargePages;
2180
+ size_t freedSmallPages;
2180
2181
size_t freed;
2181
2182
for (size_t n = 0 ; n < npools; n++ )
2182
2183
{
@@ -2244,50 +2245,96 @@ struct Gcx
2244
2245
}
2245
2246
else
2246
2247
{
2247
-
2248
2248
for (pn = 0 ; pn < pool.npages; pn++ )
2249
2249
{
2250
2250
Bins bin = cast (Bins)pool.pagetable[pn];
2251
2251
2252
2252
if (bin < B_PAGE )
2253
2253
{
2254
- immutable size = binsize[bin];
2255
- void * p = pool.baseAddr + pn * PAGESIZE ;
2256
- immutable base = pn * (PAGESIZE / 16 );
2257
- immutable bitstride = size / 16 ;
2254
+ auto freebitsdata = pool.freebits.data + pn * PageBits.length;
2255
+ auto markdata = pool.mark.data + pn * PageBits.length;
2258
2256
2259
- bool freeBits;
2257
+ // the entries to free are allocated objects (freebits == false)
2258
+ // that are not marked (mark == false)
2260
2259
PageBits toFree;
2260
+ static foreach (w; 0 .. PageBits.length)
2261
+ toFree[w] = (~ freebitsdata[w] & ~ markdata[w]);
2262
+
2263
+ // the page is unchanged if there is nothing to free
2264
+ bool unchanged = true ;
2265
+ static foreach (w; 0 .. PageBits.length)
2266
+ unchanged = unchanged && (toFree[w] == 0 );
2267
+ if (unchanged)
2268
+ continue ;
2261
2269
2262
- // ensure that there are at least <size> bytes for every address
2263
- // below ptop even if unaligned
2264
- void * ptop = p + PAGESIZE - size + 1 ;
2265
- for (size_t i; p < ptop; p += size, i += bitstride)
2270
+ // the page can be recovered if all of the allocated objects (freebits == false)
2271
+ // are freed
2272
+ bool recoverPage = true ;
2273
+ static foreach (w; 0 .. PageBits.length)
2274
+ recoverPage = recoverPage && (~ freebitsdata[w] == toFree[w]);
2275
+
2276
+ bool hasFinalizer = false ;
2277
+ debug (COLLECT_PRINTF ) // need output for each onject
2278
+ hasFinalizer = true ;
2279
+ else debug (LOGGING )
2280
+ hasFinalizer = true ;
2281
+ else debug (MEMSTOMP )
2282
+ hasFinalizer = true ;
2283
+ if (pool.finals.data)
2266
2284
{
2267
- immutable biti = base + i;
2285
+ // finalizers must be called on objects that are about to be freed
2286
+ auto finalsdata = pool.finals.data + pn * PageBits.length;
2287
+ static foreach (w; 0 .. PageBits.length)
2288
+ hasFinalizer = hasFinalizer || (toFree[w] & finalsdata[w]) != 0 ;
2289
+ }
2268
2290
2269
- if (! pool.mark.test(biti))
2291
+ if (hasFinalizer)
2292
+ {
2293
+ immutable size = binsize[bin];
2294
+ void * p = pool.baseAddr + pn * PAGESIZE ;
2295
+ immutable base = pn * (PAGESIZE / 16 );
2296
+ immutable bitstride = size / 16 ;
2297
+
2298
+ // ensure that there are at least <size> bytes for every address
2299
+ // below ptop even if unaligned
2300
+ void * ptop = p + PAGESIZE - size + 1 ;
2301
+ for (size_t i; p < ptop; p += size, i += bitstride)
2270
2302
{
2271
- void * q = sentinel_add(p);
2272
- sentinel_Invariant(q);
2303
+ immutable biti = base + i;
2273
2304
2274
- if (pool.finals.nbits && pool.finals.test(biti))
2275
- rt_finalizeFromGC(q, sentinel_size (q, size), pool.getBits(biti));
2305
+ if (! pool.mark.test(biti))
2306
+ {
2307
+ void * q = sentinel_add(p);
2308
+ sentinel_Invariant(q);
2276
2309
2277
- freeBits = true ;
2278
- toFree.set(i );
2310
+ if (pool.finals.nbits && pool.finals.test(biti))
2311
+ rt_finalizeFromGC(q, sentinel_size (q, size), pool.getBits(biti) );
2279
2312
2280
- debug (COLLECT_PRINTF ) printf(" \t collecting %p\n " , p);
2281
- leakDetector.log_free(sentinel_add(p));
2313
+ assert (core.bitop.bt (toFree.ptr, i));
2282
2314
2283
- debug (MEMSTOMP ) memset(p, 0xF3 , size);
2315
+ debug (COLLECT_PRINTF ) printf(" \t collecting %p\n " , p);
2316
+ leakDetector.log_free(sentinel_add(p));
2284
2317
2285
- freed += size;
2318
+ debug (MEMSTOMP ) memset(p, 0xF3 , size);
2319
+ }
2286
2320
}
2287
2321
}
2288
2322
2289
- if (freeBits)
2323
+ if (recoverPage)
2324
+ {
2325
+ pool.freeAllPageBits(pn);
2326
+
2327
+ pool.pagetable[pn] = B_FREE ;
2328
+ // add to free chain
2329
+ pool.binPageChain[pn] = cast (uint ) pool.searchStart;
2330
+ pool.searchStart = pn;
2331
+ pool.freepages++ ;
2332
+ freedSmallPages++ ;
2333
+ }
2334
+ else
2335
+ {
2290
2336
pool.freePageBits(pn, toFree);
2337
+ }
2291
2338
}
2292
2339
}
2293
2340
}
@@ -2296,11 +2343,16 @@ struct Gcx
2296
2343
assert (freedLargePages <= usedLargePages);
2297
2344
usedLargePages -= freedLargePages;
2298
2345
debug (COLLECT_PRINTF ) printf(" \t free'd %u bytes, %u pages from %u pools\n " , freed, freedLargePages, npools);
2299
- return freedLargePages;
2346
+
2347
+ assert (freedSmallPages <= usedSmallPages);
2348
+ usedSmallPages -= freedSmallPages;
2349
+ debug (COLLECT_PRINTF ) printf(" \t recovered small pages = %d\n " , freedSmallPages);
2350
+
2351
+ return freedLargePages + freedSmallPages;
2300
2352
}
2301
2353
2302
- // collection step 4: recover pages with no live objects, rebuild free lists
2303
- size_t recover () nothrow
2354
+ // collection step 4: rebuild free lists
2355
+ void recover () nothrow
2304
2356
{
2305
2357
// init tail list
2306
2358
List** [B_NUMSMALL ] tail = void ;
@@ -2327,27 +2379,9 @@ struct Gcx
2327
2379
if (bin < B_PAGE )
2328
2380
{
2329
2381
size_t size = binsize[bin];
2330
- size_t bitstride = size / 16 ;
2331
2382
size_t bitbase = pn * (PAGESIZE / 16 );
2332
- size_t bittop = bitbase + (PAGESIZE / 16 ) - bitstride + 1 ;
2333
- void * p;
2334
-
2335
- biti = bitbase;
2336
- for (biti = bitbase; biti < bittop; biti += bitstride)
2337
- {
2338
- if (! pool.freebits.test(biti))
2339
- goto Lnotfree;
2340
- }
2341
- pool.pagetable[pn] = B_FREE ;
2342
- // add to free chain
2343
- pool.binPageChain[pn] = cast (uint ) pool.searchStart;
2344
- pool.searchStart = pn;
2345
- pool.freepages++ ;
2346
- freedSmallPages++ ;
2347
- continue ;
2348
2383
2349
- Lnotfree:
2350
- p = pool.baseAddr + pn * PAGESIZE ;
2384
+ void * p = pool.baseAddr + pn * PAGESIZE ;
2351
2385
const top = PAGESIZE - size + 1 ; // ensure <size> bytes available even if unaligned
2352
2386
for (u = 0 ; u < top; u += size)
2353
2387
{
@@ -2365,11 +2399,6 @@ struct Gcx
2365
2399
// terminate tail list
2366
2400
foreach (ref next; tail)
2367
2401
* next = null ;
2368
-
2369
- assert (freedSmallPages <= usedSmallPages);
2370
- usedSmallPages -= freedSmallPages;
2371
- debug (COLLECT_PRINTF ) printf(" \t recovered pages = %d\n " , freedSmallPages);
2372
- return freedSmallPages;
2373
2402
}
2374
2403
2375
2404
/**
@@ -2428,18 +2457,18 @@ struct Gcx
2428
2457
start = stop;
2429
2458
2430
2459
ConservativeGC._inFinalizer = true ;
2431
- size_t freedLargePages= void ;
2460
+ size_t freedPages = void ;
2432
2461
{
2433
2462
scope (failure) ConservativeGC._inFinalizer = false ;
2434
- freedLargePages = sweep();
2463
+ freedPages = sweep();
2435
2464
ConservativeGC._inFinalizer = false ;
2436
2465
}
2437
2466
2438
2467
stop = currTime;
2439
2468
sweepTime += (stop - start);
2440
2469
start = stop;
2441
2470
2442
- immutable freedSmallPages = recover();
2471
+ recover();
2443
2472
2444
2473
stop = currTime;
2445
2474
recoverTime += (stop - start);
@@ -2451,7 +2480,7 @@ struct Gcx
2451
2480
2452
2481
updateCollectThresholds();
2453
2482
2454
- return freedLargePages + freedSmallPages ;
2483
+ return freedPages ;
2455
2484
}
2456
2485
2457
2486
/**
@@ -2808,6 +2837,25 @@ struct Pool
2808
2837
}
2809
2838
}
2810
2839
2840
+ void freeAllPageBits (size_t pagenum) nothrow
2841
+ {
2842
+ assert (! isLargeObject);
2843
+ assert (! nointerior.nbits); // only for large objects
2844
+
2845
+ immutable beg = pagenum * PageBits.length;
2846
+ static foreach (i; 0 .. PageBits.length)
2847
+ {{
2848
+ immutable w = beg + i;
2849
+ freebits.data[w] = ~ 0 ;
2850
+ noscan.data[w] = 0 ;
2851
+ appendable.data[w] = 0 ;
2852
+ if (finals.data)
2853
+ finals.data[w] = 0 ;
2854
+ if (structFinals.data)
2855
+ structFinals.data[w] = 0 ;
2856
+ }}
2857
+ }
2858
+
2811
2859
/**
2812
2860
* Given a pointer p in the p, return the pagenum.
2813
2861
*/
0 commit comments