[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;
>   }


NOTE: All email exchanges with Unidata User Support are recorded in the Unidata inquiry tracking system and then made publicly available through the web. If you do not want to have your interactions made available in this way, you must let us know in each email you send to us.