diff options
author | David Mitchell <davem@iabyn.com> | 2012-03-06 14:26:27 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2012-03-06 14:26:27 +0000 |
commit | 5bec93bead1c10563a402404de095bbdf398790f (patch) | |
tree | 6804fecb854a7340fe5301eb0577d0ebf41173a1 /hv.c | |
parent | 1cd16d8ac049ac3ffe94281e35fe9270b854408d (diff) | |
download | perl-5bec93bead1c10563a402404de095bbdf398790f.tar.gz |
fix slowdown in nested hash freeing
Commit 104d7b69 made sv_clear free hashes iteratively rather than recursively;
however, my code didn't record the current hash index when freeing a
nested hash, which made the code go quadratic when freeing a large hash
with inner hashes, e.g.:
my $r; $r->{$_} = { a => 1 } for 1..10_0000;
This was noticeable on such things as CPAN.pm being very slow to exit.
This commit fixes this by squirrelling away the old hash index in the
now-unused SvMAGIC field of the hash being freed.
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 5 |
1 files changed, 4 insertions, 1 deletions
@@ -1863,7 +1863,10 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) xhv->xhv_max = 7; /* HvMAX(hv) = 7 (it's a normal hash) */ HvARRAY(hv) = 0; } - HvPLACEHOLDERS_set(hv, 0); + /* if we're freeing the HV, the SvMAGIC field has been reused for + * other purposes, and so there can't be any placeholder magic */ + if (SvREFCNT(hv)) + HvPLACEHOLDERS_set(hv, 0); if (SvRMAGICAL(hv)) mg_clear(MUTABLE_SV(hv)); |