[Prev][Next][Index][Thread][Top, Search][Archived Lists][Original Mail]

Re: BUG REPORT: Script that demonstrates a memory leak in 5.002beta1



On Sat, 09 Dec 1995 21:12:00 GMT, Alan Burlison wrote:
>The following short script leaks like a sieve on 5.002beta1, but not at 
>all on 5.001m.  I have included some memory statistics, and the output of 
>myconfig.  Some curious things:  The number of items pushed onto the 
>anonymous array referenced by $leak is critical - any less than 125 and 
>the program size remains constant.  If $leak is changed to @leak, the 
>problem also disappears.  Could someone a) confirm that there is a 
>problem and b) if so, shed some light on what is causing it?

Here's a summary of the problem and a workaround.

The new sv_add_arena() functionality is used to reclaim AvARRAYs and
HvARRAYs that have a significantly large size.  This memory gets added as a
fresh new sv arena.  The problem arises when arrays and hashes grow beyond
these significant sizes inside loops which triggers relocation to a larger
contiguous block of memory and reclamation of the old one.  Since the
reclamation code is not cognizant of whether it is sitting inside a loop,
this amounts to unconditional scavenging (but not free()ing) of memory.

The immediate workaround is to either compile both hv.c and av.c with
-DSTRANGE_MALLOC, or apply the following slightly more efficient patch (a
bunch of ifdefs really) that always frees [HA]vARRAYs.  Until we figure out
a way to put a cap on the amount of reclaimed (but still unused) space and
make sv_add_arena() be conditional based on that, this is may be the
solution.

Doing this also eliminates all symptoms of the bug reported by Andreas a few
days back.

For reference, here are the two test cases that work fine in 5.001n:

   while (1) { $leak = {}; for (1..68) { $leak->{$_} = "z"; } }
   while (1) { $leak = []; for (1..125) { push(@$leak, "Z"); } }

 - Sarathy.
   gsar@engin.umich.edu

P.S: A couple of notes:

  * I don't know why Larry did not do a sv_add_arena() in av_undef()
    but did so in hv_undef()
  * why AvMAX(av) rather than AvMAX(av)+1 in the sv_add_arena() call in
    av_extend() ?
------------------------------------8<-----------------------------
*** av.c.dist	Wed Nov 15 14:26:17 1995
--- av.c	Sat Dec  9 23:03:32 1995
***************
*** 82,90 ****
  		newmax = tmp - 1;
  		New(2,ary, newmax+1, SV*);
  		Copy(AvALLOC(av), ary, AvMAX(av)+1, SV*);
  		if (AvMAX(av) > 64 && !AvREUSED(av))
! 		    sv_add_arena((char*)AvALLOC(av), AvMAX(av) * sizeof(SV*),0);
  		else
  		    Safefree(AvALLOC(av));
  		AvALLOC(av) = ary;
  #endif
--- 82,92 ----
  		newmax = tmp - 1;
  		New(2,ary, newmax+1, SV*);
  		Copy(AvALLOC(av), ary, AvMAX(av)+1, SV*);
+ #ifdef 0		
  		if (AvMAX(av) > 64 && !AvREUSED(av))
! 		    sv_add_arena((char*)AvALLOC(av), (AvMAX(av)+1) * sizeof(SV*),0);
  		else
+ #endif		    
  		    Safefree(AvALLOC(av));
  		AvALLOC(av) = ary;
  #endif
*** hv.c.dist	Wed Nov 15 15:00:05 1995
--- hv.c	Sat Dec  9 23:10:03 1995
***************
*** 337,342 ****
--- 337,343 ----
      assert(tmp >= newsize);
      New(2,a, tmp, HE*);
      Copy(xhv->xhv_array, a, oldsize, HE*);
+ #if 0    
      if (oldsize >= 64 && *(char*)&xhv->xnv_nv == 0) {
  	sv_add_arena((char*)xhv->xhv_array, oldsize * sizeof(HE*), 0);
  	sv_add_arena(((char*)a) + newsize * sizeof(HE*),
***************
*** 344,349 ****
--- 345,351 ----
  		     SVf_FAKE);
      }
      else
+ #endif	
  	Safefree(xhv->xhv_array);
  #endif
  
***************
*** 478,487 ****
--- 480,493 ----
  #ifdef STRANGE_MALLOC
      Safefree(xhv->xhv_array);
  #else
+ #if 0    
      if (xhv->xhv_max < 127 || *(char*)&xhv->xnv_nv)
  	Safefree(xhv->xhv_array);
      else  /* We used last half, so use first half for SV arena too. */
  	sv_add_arena((char*)xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*),0);
+ #else
+     Safefree(xhv->xhv_array);
+ #endif    
  #endif
      if (HvNAME(hv)) {
  	Safefree(HvNAME(hv));


References: