fix leak related to object counts

When collecting to the maximum generation with object counts enabled,
a structure type would effectively become permanently reachable.

Also, add `bytes-finalized` to report how many bytes were associated
with guardian-based finalization by the most recent collection.

original commit: 852f5e2de95a26d3500321c4d4d732407945a57a
This commit is contained in:
Matthew Flatt 2020-04-16 16:16:13 -06:00
parent d540162c0d
commit c4ffe39efb
12 changed files with 85 additions and 34 deletions

View File

@ -168,6 +168,10 @@ ptr S_compute_bytes_allocated(xg, xs) ptr xg; ptr xs; {
return Sunsigned(n); return Sunsigned(n);
} }
ptr S_bytes_finalized() {
return Sunsigned(S_G.bytes_finalized);
}
static void maybe_fire_collector() { static void maybe_fire_collector() {
ISPC s; ISPC s;
uptr bytes, fudge; uptr bytes, fudge;

View File

@ -64,6 +64,7 @@ extern void S_protect PROTO((ptr *p));
extern void S_reset_scheme_stack PROTO((ptr tc, iptr n)); extern void S_reset_scheme_stack PROTO((ptr tc, iptr n));
extern void S_reset_allocation_pointer PROTO((ptr tc)); extern void S_reset_allocation_pointer PROTO((ptr tc));
extern ptr S_compute_bytes_allocated PROTO((ptr xg, ptr xs)); extern ptr S_compute_bytes_allocated PROTO((ptr xg, ptr xs));
extern ptr S_bytes_finalized PROTO(());
extern ptr S_find_more_room PROTO((ISPC s, IGEN g, iptr n, ptr old)); extern ptr S_find_more_room PROTO((ISPC s, IGEN g, iptr n, ptr old));
extern void S_dirty_set PROTO((ptr *loc, ptr x)); extern void S_dirty_set PROTO((ptr *loc, ptr x));
extern void S_scan_dirty PROTO((ptr **p, ptr **endp)); extern void S_scan_dirty PROTO((ptr **p, ptr **endp));

24
c/gc.c
View File

@ -21,8 +21,6 @@
#endif /* WIN32 */ #endif /* WIN32 */
#include "popcount.h" #include "popcount.h"
#define enable_object_counts do_not_use_enable_object_counts_in_this_file_use_ifdef_ENABLE_OBJECT_COUNTS_instead
/* locally defined functions */ /* locally defined functions */
static uptr list_length PROTO((ptr ls)); static uptr list_length PROTO((ptr ls));
static ptr copy_list PROTO((ptr ls, IGEN tg)); static ptr copy_list PROTO((ptr ls, IGEN tg));
@ -66,6 +64,7 @@ static void sanitize_locked_segment PROTO((seginfo *si));
#ifdef ENABLE_OBJECT_COUNTS #ifdef ENABLE_OBJECT_COUNTS
static uptr total_size_so_far(); static uptr total_size_so_far();
#endif #endif
static uptr target_generation_space_so_far();
#ifdef ENABLE_MEASURE #ifdef ENABLE_MEASURE
static void init_measure(IGEN min_gen, IGEN max_gen); static void init_measure(IGEN min_gen, IGEN max_gen);
@ -360,6 +359,7 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
seginfo *oldspacesegments, *si, *nextsi; seginfo *oldspacesegments, *si, *nextsi;
ptr ls, younger_locked_objects; ptr ls, younger_locked_objects;
bucket_pointer_list *buckets_to_rebuild; bucket_pointer_list *buckets_to_rebuild;
uptr pre_finalization_size;
#ifdef ENABLE_OBJECT_COUNTS #ifdef ENABLE_OBJECT_COUNTS
ptr count_roots_counts = Snil; ptr count_roots_counts = Snil;
iptr count_roots_len; iptr count_roots_len;
@ -633,6 +633,8 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
sweep_generation(tc, tg); sweep_generation(tc, tg);
pre_finalization_size = target_generation_space_so_far();
/* handle guardians */ /* handle guardians */
{ ptr hold_ls, pend_hold_ls, final_ls, pend_final_ls, maybe_final_ordered_ls; { ptr hold_ls, pend_hold_ls, final_ls, pend_final_ls, maybe_final_ordered_ls;
ptr obj, rep, tconc, next; ptr obj, rep, tconc, next;
@ -843,6 +845,8 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
S_G.guardians[tg] = hold_ls; S_G.guardians[tg] = hold_ls;
} }
S_G.bytes_finalized = target_generation_space_so_far() - pre_finalization_size;
/* handle weak pairs */ /* handle weak pairs */
resweep_dirty_weak_pairs(); resweep_dirty_weak_pairs();
resweep_weak_pairs(tg); resweep_weak_pairs(tg);
@ -898,8 +902,10 @@ ptr GCENTRY(ptr tc, IGEN mcg, IGEN tg, ptr count_roots_ls) {
/* rebuild rtds_with_counts lists, dropping otherwise inaccessible rtds */ /* rebuild rtds_with_counts lists, dropping otherwise inaccessible rtds */
{ IGEN g; ptr ls, p, newls = tg == mcg ? Snil : S_G.rtds_with_counts[tg]; seginfo *si; { IGEN g; ptr ls, p, newls = tg == mcg ? Snil : S_G.rtds_with_counts[tg]; seginfo *si;
int count = 0;
for (g = 0; g <= mcg; g += 1) { for (g = 0; g <= mcg; g += 1) {
for (ls = S_G.rtds_with_counts[g], S_G.rtds_with_counts[g] = Snil; ls != Snil; ls = Scdr(ls)) { for (ls = S_G.rtds_with_counts[g], S_G.rtds_with_counts[g] = Snil; ls != Snil; ls = Scdr(ls)) {
count++;
p = Scar(ls); p = Scar(ls);
si = SegInfo(ptr_get_segment(p)); si = SegInfo(ptr_get_segment(p));
if (!(si->space & space_old) || locked(si, p)) { if (!(si->space & space_old) || locked(si, p)) {
@ -1855,6 +1861,20 @@ static uptr total_size_so_far() {
} }
#endif #endif
static uptr target_generation_space_so_far() {
IGEN g = target_generation;
ISPC s;
uptr sz = S_G.phantom_sizes[g];
for (s = 0; s <= max_real_space; s++) {
sz += S_G.bytes_of_space[s][g];
if (S_G.next_loc[s][g] != FIX(0))
sz += (char *)S_G.next_loc[s][g] - (char *)S_G.base_loc[s][g];
}
return sz;
}
/* **************************************** */ /* **************************************** */
#ifdef ENABLE_MEASURE #ifdef ENABLE_MEASURE

View File

@ -411,8 +411,11 @@ ptr S_object_backreferences(void) {
*/ */
void Scompact_heap() { void Scompact_heap() {
ptr tc = get_thread_context(); ptr tc = get_thread_context();
IBOOL eoc = S_G.enable_object_counts;
S_pants_down += 1; S_pants_down += 1;
S_G.enable_object_counts = 1;
S_gc_oce(tc, S_G.max_nonstatic_generation, static_generation, Sfalse); S_gc_oce(tc, S_G.max_nonstatic_generation, static_generation, Sfalse);
S_G.enable_object_counts = eoc;
S_pants_down -= 1; S_pants_down -= 1;
} }

View File

@ -137,6 +137,7 @@ EXTERN struct S_G_struct {
ptr gcbackreference[static_generation+1]; ptr gcbackreference[static_generation+1];
uptr phantom_sizes[static_generation+1]; uptr phantom_sizes[static_generation+1];
IGEN prcgeneration; IGEN prcgeneration;
uptr bytes_finalized;
/* intern.c */ /* intern.c */
iptr oblist_length; iptr oblist_length;

View File

@ -170,6 +170,7 @@ void S_prim_init() {
Sforeign_symbol("(cs)fixedpathp", (void *)S_fixedpathp); Sforeign_symbol("(cs)fixedpathp", (void *)S_fixedpathp);
Sforeign_symbol("(cs)bytes_allocated", (void *)S_compute_bytes_allocated); Sforeign_symbol("(cs)bytes_allocated", (void *)S_compute_bytes_allocated);
Sforeign_symbol("(cs)bytes_finalized", (void *)S_bytes_finalized);
Sforeign_symbol("(cs)curmembytes", (void *)S_curmembytes); Sforeign_symbol("(cs)curmembytes", (void *)S_curmembytes);
Sforeign_symbol("(cs)maxmembytes", (void *)S_maxmembytes); Sforeign_symbol("(cs)maxmembytes", (void *)S_maxmembytes);
Sforeign_symbol("(cs)resetmaxmembytes", (void *)S_resetmaxmembytes); Sforeign_symbol("(cs)resetmaxmembytes", (void *)S_resetmaxmembytes);

View File

@ -4829,6 +4829,18 @@ still in use or not, can be obtained by summing
\scheme{(bytes-deallocated)} and \scheme{(bytes-allocated)} \scheme{(bytes-deallocated)} and \scheme{(bytes-allocated)}
and possibly subtracting \scheme{(initial-bytes-allocated)}. and possibly subtracting \scheme{(initial-bytes-allocated)}.
%----------------------------------------------------------------------------
\entryheader
\formdef{bytes-finalized}{\categoryprocedure}{(bytes-finalized)}
\returns the number of bytes queued in guardians
\listlibraries
\endentryheader
The number of bytes associated with objects that were registered in
guardians as otherwise inaccessible (including the bytes for objects
reachable only through registered objects) during the most recent
garbage collection.
%---------------------------------------------------------------------------- %----------------------------------------------------------------------------
\entryheader \entryheader
\formdef{current-memory-bytes}{\categoryprocedure}{(current-memory-bytes)} \formdef{current-memory-bytes}{\categoryprocedure}{(current-memory-bytes)}

View File

@ -62,7 +62,7 @@ InstallLZ4Target=
# no changes should be needed below this point # # no changes should be needed below this point #
############################################################################### ###############################################################################
Version=csv9.5.3.25 Version=csv9.5.3.26
Include=boot/$m Include=boot/$m
PetiteBoot=boot/$m/petite.boot PetiteBoot=boot/$m/petite.boot
SchemeBoot=boot/$m/scheme.boot SchemeBoot=boot/$m/scheme.boot

7
s/7.ss
View File

@ -86,6 +86,13 @@
[(g) (ba (filter-generation g) -1)] [(g) (ba (filter-generation g) -1)]
[(g s) (ba (if g (filter-generation g) -1) (if s (filter-space s) -1))]))) [(g s) (ba (if g (filter-generation g) -1) (if s (filter-space s) -1))])))
(define-who bytes-finalized
(let ([bf (foreign-procedure "(cs)bytes_finalized"
()
scheme-object)])
(lambda ()
(bf))))
(define $spaces (lambda () (map car (constant real-space-alist)))) (define $spaces (lambda () (map car (constant real-space-alist))))
(define current-memory-bytes (foreign-procedure "(cs)curmembytes" () uptr)) (define current-memory-bytes (foreign-procedure "(cs)curmembytes" () uptr))

View File

@ -328,7 +328,7 @@
[(_ foo e1 e2) e1] ... [(_ foo e1 e2) e1] ...
[(_ bar e1 e2) e2]))))]))) [(_ bar e1 e2) e2]))))])))
(define-constant scheme-version #x09050319) (define-constant scheme-version #x0905031A)
(define-syntax define-machine-types (define-syntax define-machine-types
(lambda (x) (lambda (x)

View File

@ -746,6 +746,7 @@
[copy [copy
(case-flag counts? (case-flag counts?
[on [on
(when S_G.enable_object_counts
(let* ([c_rtd : ptr (cond (let* ([c_rtd : ptr (cond
[(== _tf_ _) _copy_] [(== _tf_ _) _copy_]
[else rtd])] [else rtd])]
@ -765,18 +766,18 @@
(set! g += 1))) (set! g += 1)))
(set! (record-type-counts c_rtd) counts) (set! (record-type-counts c_rtd) counts)
(set! (array-ref S_G.rtds_with_counts grtd) (set! (array-ref S_G.rtds_with_counts grtd)
(S_cons_in (cond [(== grtd 0) space_new] [else space_impure]) grtd c_rtd ;; this list will get copied again in `rtds_with_counts` fixup
(array-ref S_G.rtds_with_counts grtd))) (S_cons_in space_new 0 c_rtd (array-ref S_G.rtds_with_counts grtd)))
(set! (array-ref (array-ref S_G.countof grtd) countof_pair) += 1))] (set! (array-ref (array-ref S_G.countof grtd) countof_pair) += 1))]
[else [else
(trace-early (just counts)) (trace-early (just counts))
(set! (record-type-counts c_rtd) counts) (set! (record-type-counts c_rtd) counts)
(when (!= (rtd-counts-timestamp counts) (array-ref S_G.gctimestamp 0)) (when (!= (rtd-counts-timestamp counts) (array-ref S_G.gctimestamp 0))
(S_fixup_counts counts))]) (S_fixup_counts counts))])
(set! (rtd-counts-data counts tg) (+ (rtd-counts-data counts tg) 1)) (set! (rtd-counts-data counts tg) (+ (rtd-counts-data counts tg) 1))))
;; Copies size that we've already gathered, but needed for counting from roots: ;; Copies size that we may have already gathered, but needed for counting from roots:
(when (== p_spc space-count-impure) (set! count_root_bytes += p_sz)) (when (== p_spc space-count-impure) (set! count_root_bytes += p_sz))
(count countof-record))] (count countof-record)]
[off])] [off])]
[else])) [else]))

View File

@ -1165,6 +1165,7 @@
(bwp-object? [sig [(ptr) -> (boolean)]] [flags pure unrestricted mifoldable discard]) (bwp-object? [sig [(ptr) -> (boolean)]] [flags pure unrestricted mifoldable discard])
(bytes-allocated [sig [() -> (uint)] [(ptr) -> (uint)] [(ptr maybe-sub-symbol) -> (uint)]] [flags alloc]) (bytes-allocated [sig [() -> (uint)] [(ptr) -> (uint)] [(ptr maybe-sub-symbol) -> (uint)]] [flags alloc])
(bytes-deallocated [sig [() -> (uint)]] [flags unrestricted alloc]) (bytes-deallocated [sig [() -> (uint)]] [flags unrestricted alloc])
(bytes-finalized [sig [() -> (uint)]] [flags unrestricted alloc])
(bytevector [sig [(u8/s8 ...) -> (bytevector)]] [flags alloc cp02]) (bytevector [sig [(u8/s8 ...) -> (bytevector)]] [flags alloc cp02])
(bytevector->s8-list [sig [(bytevector) -> (list)]] [flags alloc]) (bytevector->s8-list [sig [(bytevector) -> (list)]] [flags alloc])
(bytevector-truncate! [sig [(bytevector length) -> (bytevector)]] [flags true]) (bytevector-truncate! [sig [(bytevector length) -> (bytevector)]] [flags true])