Menu

#4432 dict incr leaks

obsolete: 8.5.7
closed-fixed
9
2009-10-08
2009-10-08
No

If a dict is created and filled via "dict incr" with a bigger set of keys it seems to leak. If the dict is destroyed (unset or overwritten) a lot of memory still keeps allocated.

The following code consumes approx. 500MB memory on my machine (Linux, 64-bit):

set chars {a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9}

for {set i 0} {$i < 1000} {incr i} {
append prefix [lindex $chars [expr int([tcl::mathfunc::rand]*62)]]
set dictionary [dict create]
foreach char $chars {
foreach c $chars {
dict incr dictionary $prefix$char$c $i
}
}
}

I've tested Tcl 8.5.2 (OpenSuSE 11.0, x86_64), 8.5.7, 8.6b1 (both built from source),
all three leak, cf. attached valgrind log files for same code but only 100 cycles.

For 8.5.2 TclBN_mp_init_size according to valgrind seems to be reason.

% uname -mrvs
Linux 2.6.25.20-0.5-default #1 SMP 2009-08-14 01:48:11 +0200 x86_64

Discussion

  • Sebastian Nagel

    Sebastian Nagel - 2009-10-08

    valgrind log files for

     
  • Sebastian Nagel

    Sebastian Nagel - 2009-10-08

    May the patch below fix the problem?

    --- ./generic/tclDictObj.c~ 2009-01-06 17:07:17.000000000 +0100
    +++ ./generic/tclDictObj.c 2009-10-08 15:00:29.000000000 +0200
    @@ -2148,6 +2148,7 @@
    mp_int increment;

    code = Tcl_GetBignumFromObj(interp, objv[3], &increment);
    + mp_clear(&increment);
    if (code != TCL_OK) {
    Tcl_AddErrorInfo(interp, "\n (reading increment)");
    } else {

     
  • Donal K. Fellows

    • priority: 5 --> 9
     
  • Donal K. Fellows

    Leaks 8 words per *interpreted* [dict incr] that creates a dictionary entry.

     
  • Donal K. Fellows

    And requires an explicit increment to do so.

     
  • Donal K. Fellows

    The following test seems to be exact:

    test dict-19.3 {dict: testing for leaks - Bug 2874678} -setup {
    proc memtest script {
    set end [lindex [split [memory info] \n] 3 3]
    for {set i 0} {$i < 5} {incr i} {
    uplevel 1 $script
    set tmp $end
    set end [lindex [split [memory info] \n] 3 3]
    }
    expr {$end - $tmp}
    }
    } -constraints memory -body {
    set d aDictVar; # Force interpreted [dict incr]
    memtest {
    dict incr $d aKey 0
    unset $d
    }
    } -cleanup {
    unset d
    rename memtest {}
    } -result 0

     
  • Donal K. Fellows

    Fixed in HEAD and 8.5 (the patch was slightly wrong, but helped narrow down what needed to be done a lot; thanks!)

     
  • Donal K. Fellows

    • status: open --> closed-fixed