[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
20010926: Memory leak in udunits library using RH Linux
- Subject: 20010926: Memory leak in udunits library using RH Linux
- Date: Wed, 26 Sep 2001 12:23:30 -0600
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;
> }