[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

20010926: Memory leak in udunits library using RH Linux



Scott,

Thank you very much for notifying me about this.  I'll look into it.

Regards,
Steve Emmerson   <http://www.unidata.ucar.edu>

> cc: address@hidden
> From: "Scott O'Donnell" <address@hidden>
> Subject: Memory leak in udunits library using RH Linux
> Organization: NOAA/Forecast Systems Laboratory
> Keywords: 200109261727.f8QHRm116517 UDUNITS RedHat Linux
>
> I've recently been trying to resolve a significant memory leak in a
> program I'm  writing.  I have isolated the leak to the udunits library.
> I've rearranged my code and can avoid the memory leak and gain some 
> performance improvement, so this is no crisis for me and I can 
> continue to use your convenient and flexible library.
> 
> However, I thought I should bring this problem to your attention.
> 
> 
> I wrote a small program that  consistently reproduces the error in my
> working environment.  You will find my test program source code attached 
> to this message for your further evaluation.  The compile and execution 
> instructions are included in the source code prologue.
> 
> I work on a Dell PC, with dual Pentium III cpus, run RedHat 6.2 Linux, 
> and use the Gnome window manager.  
> 
> I've compiled this code and the udunits library using  gcc-2.95.2 and 
> gcc-2.95.3 on this platform.  I ensured that the udunits library and my 
> test code was built consistently using similar compiler versions in each 
> test evaluation (although, I don't believe this precaution was absolutely 
> necessary).  I also ran my tests on another Linux platform running RH 7.1,
> after recompiling, using the gcc-2.95.2, gcc-2.95.3, gcc-3.0 compilers.
> 
> In each case, on Linux platforms, not all the memory allocated to udunits 
> is returned to the heap.  There doesn't seem to be any upper limit to memory 
> used, with a uniform amount of memory leakage  on each iteration.   I used 
> 'top' to verify my assumption on the amount and rate of memory increase.
> 
> I also ran my test program on a HP C110, running  HPUX 10.0 and used 
> the gcc-2.95.3 compiler.  On this platform, I used 'purify' to verify that 
> the code runs cleanly, with no memory leaks at all!
> 
> My conclusion is that there is an error in the Linux implementation of either 
> (or both) 'twalk' used in function utTerm() or 'tdelete' used in function 
> NodeDeleter() on which udunits depends so heavily to release the previously 
> allocated memory.
> 
> 
> If you have additional questions, please feel free to contact me,
> 
> Scott O'Donnell
> address@hidden
> 303.497.6562
> 
> 
> -- 
> If all of us are wounded, will revenge work?    |       Scott O'Donnell
> Won't an eye for an eye, a tooth for a tooth,   | address@hidden
> and  a limb for a  limb, leave us all           |          303.497.6562
> blind, toothless, and crippled?    -D.Chopra
> --------------F7D230D8BD81B3267959891D
> Content-Type: text/plain; charset=us-ascii;
>  name="testUdunits.c"
> Content-Transfer-Encoding: 7bit
> Content-Disposition: inline;
>  filename="testUdunits.c"
> 
> /* -----------------------------------------------------------------
> // This software is in the public domain, furnished "as is", 
> //   without technical support, and with no warranty, express 
> //   or implied, as to its usefulness for any purpose.
> // -------------------------------------------------------------
> //
> // testUdunits.c
> //    This is a simple program to test the memory allocation and 
> //        release of the Unidata udunits package.
> //
> // -------------------------------------------------------------
> //  This  test program is intended to be compiled using a C++ compiler,
> //     although it uses few C++ elements.
> //   
> //
> //  Using a Linux OS (i.e. RH 6.2 or RH 7.1) and the tcsh shell,
> //    use these commands to compile:
> //
> //    setenv UDUNITS_DIR    /usr/local/udunits
> //    setenv COMPILER_DIR   /usr/local/gcc-2.95.3
> //    ${COMPILER_DIR}/bin/c++ -I ${UDUNITS_DIR}/include testUdunits.c \
> //           -o testUdunits -L ${UDUNITS_DIR}/udunits-1.11.7/lib -ludunits
> //  
> //
> // Author: S.O'Donnell
> // -------------------------------------------------------------
> // ------------------------------------------------------------- */
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> 
> 
> #if defined(__cplusplus) || defined(c_plusplus)
> extern "C"
>   {
>   #include "udunits.h"
>   }
> #else
>      #include "udunits.h"
> #endif
> 
> 
> /* --------------------------------------------- *
>  * This function converts "value" in "fromString" units
>  *    into "toString" units, using the slope-intercept method,
>  *    returning the result in "result".  
>  *  Successful completion returns 0,
>  *    otherwise the error from the failed function call is returned.  
>  * --------------------------------------------- */
> static int udunitsConvert (double value, char *fromUnits, char *toUnits, 
>                            double& result)
>   {
>   int status=0;
>   utUnit fromUnit, toUnit;
> 
>   printf ("udunitsConvert(): %f %s to %s\n", value, fromUnits, toUnits);
> 
>   if ((status=utScan (fromUnits, &fromUnit)) != 0)
>     printf ("Unable to utScan() \"%s\"\n", fromUnits);
> 
>   else if ((status=utScan (toUnits, &toUnit)) != 0)
>     printf ("Unable to utScan() \"%s\"\n", toUnits);
> 
>   else
>     {
>     double slope, intercept;
>     
>     if ((status=utConvert(&fromUnit, &toUnit, &slope, &intercept))  != 0)
>       printf ("Unable to utConvert from %s to %s\n", 
>                                                  fromUnits, toUnits);
>     else
>       {
>       result = intercept+slope*value;
>       /*      printf ("\t%f+ (%f*%f)= %f\n",
>                             intercept,slope,value, *result);  */
>       printf ("\t%f %s = %f %s\n",
>                                   value, fromUnits, result, toUnits);
>       }
>     }    
>   return status;
>   }
> 
> /* --------------------------------------------- */
> /* demonstrate that the conversion routines work correctly... */
> /* --------------------------------------------- */
> static void  udunitsTemperatureTest ()
>     {
>     printf ("Udunit_Test2():\n");
>     double result;
> 
>     double dataValue1  =  32.0;
>     double dataValue2  = 100.0;
>     double dataValue3  =   0.0;
>     double dataValue4  = -40.0;
>     
>     char *unitString1 ="degF";
>     char *unitString2 ="degC";
>     char *unitString3 ="degK";
> 
>     /* convert degF to degC */
>     udunitsConvert (dataValue1, unitString1, unitString2, result);
>     udunitsConvert (dataValue2, unitString1, unitString2, result);
>     udunitsConvert (dataValue3, unitString1, unitString2, result);
>     udunitsConvert (dataValue4, unitString1, unitString2, result);
> 
>     /* convert degC to degF */
>     udunitsConvert (dataValue1, unitString2, unitString1, result);
>     udunitsConvert (dataValue2, unitString2, unitString1, result);
>     udunitsConvert (dataValue4, unitString2, unitString1, result);
> 
>     /* convert degC to degK */
>     udunitsConvert (dataValue2, unitString2, unitString3, result);
>     udunitsConvert (dataValue3, unitString2, unitString3, result);
>     udunitsConvert (dataValue4, unitString2, unitString3, result);
> 
>     /* convert degF to degK */
>     udunitsConvert (dataValue1, unitString1, unitString3, result);
>     udunitsConvert (dataValue3, unitString1, unitString3, result);
>     udunitsConvert (dataValue4, unitString1, unitString3, result);
> 
>     /* convert degK to degF */
>     udunitsConvert (dataValue2, unitString3, unitString1, result);
>     
>     return;
>     }
> 
> /* --------------------------------------------- */
> /*   alloc the udunits object, read the udunits.dat file */
> /* --------------------------------------------- */
> static int initUdunits()
>     {
>     char udUnitsPath[100];
>     char udUnitsFilename[256];
>     
>     strcpy (udUnitsPath,     getenv("UDUNITS_PATH"));
>     strcpy (udUnitsFilename, udUnitsPath);
>     strcat (udUnitsFilename, "/udunits.dat");    
> 
>     int status = utInit(udUnitsFilename);
>     
>     return status;
>     }
> 
> /* --------------------------------------------- */
> /* the udunits "constructor"                     */
> /* --------------------------------------------- */
> static bool  udunitsConstructor(const int i)
>   {
>   printf ("alloc iteration:  %d\n", i);
> 
>   initUdunits();
>   return true;
>   }
>     
> /* --------------------------------------------- */
> /* the udunits "destructor"                      */
> /* --------------------------------------------- */
> static bool udunitsDestructor(const int i)
>   {
>   printf ("dealloc iteration: %d\n", i); 
>   
>   utTerm();  
>   return true;
>  
>   }
>     
> /* --------------------------------------------- */
> /* default implememtation:                       */
> /*     Usage: testUdunits -i 1 -t 1              */
> /*                                               */
> /* --------------------------------------------- */
> static void Usage (char* arg0)
>   {
>   printf ("\tUsage: %s [-i <number of iterations>]\n", arg0);
>   exit (-1);
>   return;
>   }
>     
> /* --------------------------------------------- */
> static void getArgs (int argc, char **argv, int &iterations, int &waitTime)
>   {
>   int    ind;
>   extern char *optarg;
>  
>   while ((ind = getopt(argc, argv, "i:t:?")) != -1)
>     {
>     switch (ind) 
>       {
>       case 'i':
>         iterations = atoi (optarg);
>         break;
>         
>       case 't':
>         waitTime = atoi(optarg);
>         break;
> 
>       case '?':
>       default:
>         Usage (argv[0]);
>         break;
>       }
>     }
>   return;
>   }
> 
> /* --------------------------------------------- */
> /*                                               */
> /* --------------------------------------------- */
> int main (int argc, char** argv)
>   {
>   int iterations = 1;
>   int waitTime   = 1;
>   
>   getArgs(argc, argv, iterations, waitTime);
>   printf ("%s -i %d -t %d\n", argv[0], iterations, waitTime);
> 
>   int i=0;
>   while (i < iterations)
>     {
>     /* separate the 'iterations' */
>     printf ("\n");    
>     printf ("------------\n");
> 
>     /* allocate memory and initilaize the udunits object */
>     udunitsConstructor (i);
> 
>     /* demonstrate that the udunits conversion routines work correctly... */
>     udunitsTemperatureTest ();
>     printf ("\n");    
>      
>     /* release the memory allocated for the udunits object */
>     udunitsDestructor (i);
> 
>     sleep (waitTime);
>     i++;
>     }
>   
>   sleep(3);
> 
>   return 0;
>   }