ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  Is memory released when you unload libchartdir.so in your program?
Posted by Andrew Artajos on Sep-18-2012 10:42
I have a C++ application loading libchartdir.so.5 dynamically. I am experiencing memory leak specifically when makeChart is called.

4,776 bytes in 1 blocks are possibly lost in loss record 872 of 884
   at 0x4005903: malloc (vg_replace_malloc.c:195)
   by 0x420418C: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4417136: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4417045: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4417236: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4289044: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x43CC825: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4423145: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x418ECCE: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4164F04: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x421625F: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x43C13B1: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4209D5C: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x4209DB5: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x42080BA: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x415C08C: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
   by 0x87AAA5E: BaseChart::makeChart(char const*) (chartdir.h:973)

Does libchartdir.so release memory when it is dynamically unloaded by the C++ application? Anyone experiencing the same problem?

Thanks.

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Peter Kwan on Sep-18-2012 23:35
Hi Andrew,

ChartDirector may allocate some memory as cache internally. This memory usage will not grow no matter how many charts you have created, so it is not really a leak. However, ChartDirector may never release the memory.

So for your case, does the memory usage grows without limit when your code repeatedly creates many charts? If the memory usage does not grow, it can be confirmed there is no memory leak.

Regards
Peter Kwan

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Mohamed Bana on Sep-19-2012 00:00
Hi, I am responding on behalf of my colleague who has left the office until tomorrow.

Could you please help us by answering _all_ the questions below:

a) Is there is a version of the library with debug symbols so we get the names of the
functions in the callstack?
b) What sort of memory allocation scheme is taking place behind the scenes?
c) Is the memory released when we dynamically unload the library?

We are seeing a continual memory increase every time we call
BaseChart::makeChart(), see stacktrace [1].

Regards, Mohamed

---

Info (shouldn't make a difference I hope):

libchartdir.so 5.0.2
Linux x86

$ uname -a
Linux localhost.localdomain 2.6.18-308.11.1.el5PAE #1 SMP Tue Jul 10 09:29:33 EDT
2012 i686 i686 i386 GNU/Linux
$ lsb_release -a
LSB Version:    :core-4.0-ia32:core-4.0-noarch:graphics-4.0-ia32:graphics-4.0-
noarch:printing-4.0-ia32:printing-4.0-noarch
Distributor ID: CentOS
Description:    CentOS release 5.8 (Final)
Release:        5.8
Codename:       Final
[dev@localhost]$

---

[1]
Stacktrace of peak allocation as reported by Valgrind massif:

--------------------------------------------------------------------------------
  n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
--------------------------------------------------------------------------------
30 12,428,216,006       11,443,008       10,454,055       988,953            0
91.36% (10,454,055B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->41.46% (4,743,930B) 0x420118B: ??? (in /home/aartajos/gateway/lib/libchartdir.so.5.0)
| ->19.49% (2,230,066B) 0x42012CE: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | ->19.43% (2,223,600B) 0x44716CD: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | | ->19.43% (2,223,600B) 0x445501C: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | |   ->19.43% (2,223,600B) 0x4454138: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | |     ->19.43% (2,223,600B) 0x42055C4: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | |       ->19.43% (2,223,600B) 0x415908B: ??? (in
/home/aartajos/gateway/lib/libchartdir.so.5.0)
| | |         ->19.43% (2,223,600B) 0x8762A15: BaseChart::makeChart(char const*)
(chartdir.h:973)
| | |           ->19.43% (2,223,600B) 0x875DB14:
Geneos::ExpressReports::GraphVisualiser::visualise(String const&)
(GraphVisualiser.cpp:209)
| | |             ->19.43% (2,223,600B) 0x87B20AA:
Geneos::ExpressReports::TrendReport::generateGraphHtml(String const&, String const&,
String const&, String const&, VectorMap const&,
Geneos::ExpressReports::HtmlFragment&, Vector&, int,
Geneos::ExpressReports::HtmlFragment&) (TrendReport.cpp:2355)
| | |               ->19.43% (2,223,600B) 0x87AF4BC:
Geneos::ExpressReports::TrendReport::generateReportByManagedEntity(String const&,
String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&,
Vector&) (TrendReport.cpp:1952)
| | |               | ->19.43% (2,223,600B) 0x87A68A8:
Geneos::ExpressReports::TrendReport::build() (TrendReport.cpp:656)
| | |               |   ->19.43% (2,223,600B) 0x8775E6A:
Geneos::ExpressReports::ReportingComponent::build(String const&, String const&)
(ReportingComponent.cpp:12)
| | |               |     ->19.43% (2,223,600B) 0x877BC08:
Geneos::ExpressReports::ReportRun::build() (ReportRun.cpp:147)
| | |               |       ->19.43% (2,223,600B) 0x8775E6A:
Geneos::ExpressReports::ReportingComponent::build(String const&, String const&)
(ReportingComponent.cpp:12)
| | |               |         ->19.43% (2,223,600B) 0x8738141: reportRunner
(ExpressReportsManager.cpp:519)
| | |               |           ->19.43% (2,223,600B) 0x40E830: start_thread (in
/lib/libpthread-2.5.so)
| | |               |             ->19.43% (2,223,600B) 0x34E0AC: clone (in /lib/libc-2.5.so)

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Peter Kwan on Sep-20-2012 00:44
Hi Mohamed,

Before tracing into ChartDirector, is it possible to confirm for sure there is a memory leak? If the memory is leaked everytime you call makeChart, it should be very easy to check. You can just make a program that creates ten charts, and use valgrind to check the memory leak, and then modify the program to create one hundred charts, and check the memory leak again. If valgrind reports the same amount of leak for 10 charts or 100 charts, it means there is no actual leak at all.

I suggest using the following code (modified from the Simple Bar Chart sample code) for testing. In the code, you can see there is a loop to create 100 charts. You can modify the loop to create 10 charts or any number of charts. You can then use valgrind to check if the amount of memory leak is the same irrespective of the number of charts (which means there is no actual leak), or increases when the number of charts increase.


#include "chartdir.h"

int main(int argc, char *argv[])
{
    // The data for the bar chart
    double data[] = {85, 156, 179.5, 211, 123};

    // The labels for the bar chart
    const char *labels[] = {"Mon", "Tue", "Wed", "Thu", "Fri"};

for (int i = 0; i < 100; ++i)
{
    // Create a XYChart object of size 250 x 250 pixels
    XYChart *c = new XYChart(250, 250);

    // Set the plotarea at (30, 20) and of size 200 x 200 pixels
    c->setPlotArea(30, 20, 200, 200);

    // Add a bar chart layer using the given data
    c->addBarLayer(DoubleArray(data, (int)(sizeof(data) / sizeof(data[0]))));

    // Set the labels on the x axis.
    c->xAxis()->setLabels(StringArray(labels, (int)(sizeof(labels) / sizeof(labels[0]
        ))));

    // Output the chart
    c->makeChart("simplebar.png");

    //free up resources
    delete c;
}

    return 0;
}


The reason why valgrind sometimes will report incorrect memory leaks is because it is normal and common to not to release memory when the program exit. The Linux C runtime (libc, libdl), as well as the standard libraries that come with gcc (libgcc_s.so, the STL library, etc), may all cause memory to be allocated but do not release them. Since the program is shutting down anyway, there is no harm not to release the memory. The valgrind has an internal database that can filter out these "leaks" due to the Linux OS or common libraries, so you do not see valgrind reporting them.

However, ChartDirector is compiled on a different Linux, using a different compiler version, on a different Linux, linking to a different libgcc_s and STL. It is possible valgrind may not know how to filter the "leaks" from these source. So it may report leaks that are not usually consider as leaks.

So the most reliable method to confirm leaks is to repeating run the code many times, to see if the leak increases or not. If the leak does not increase, there is probably no actual leak.


For your "stacktrace [1]", from my understanding, it only shows the peak memory used. It does not show whether it is a leak or not. If ChartDirector actually leaks something like 10MB of memory, it should be very easy to verify. For the peak memory usage, as ChartDirector is basically a computer graphics program, it is normal it uses more memory than a text processing program, and it is common that the peak memory usage occurs in the computer graphics code (that is, in ChartDirector code). Using a few MB of memory is not unusual for a computer graphics program.


For your 3 questions:

(a) We do not usually provide the library with debug symbols. In any case, it is unlikely your system can use the debug symbols, because for C++, different versions of gcc generate different symbols, and your system may not understand the symbols generate by our version of gcc. It is more useful if we can come up some code that can reproduce the issue (eg. by modifying the "Simple Bar Chart" sample code above) for us to debug it.

(b) We just use normal memory allocation in C/C++, like malloc, new, etc.. Note that in C++, many libraries such as std::string, std::map, std::vector, etc., has a lot of internal memory allocations. It is not known what type of memory allocations they are using.

(c) Our code does release all memory. However, as explained above, it does not mean all memory are actually released, because there can be memory allocated by the compiler generated code or other system library. An example is memory related to RTTI (runtime type identification), which is automatically generated by the compiler, and may never be released.


Regards
Peter Kwan

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Mohamed Bana on Sep-21-2012 22:13
Thank you for your detailed reply.

You are probably right that this is not a leak.  Repeated calls to BaseChart::makeChart() does not cause it to use more memory; the initial call to BaseChart::makeChart() however does!  The memory increase we have observed is quite large - ~10mb, even more at certain times.

We are using ChartDirector ver. 5.0.2.

a. How much memory are you requesting?  I could work this out myself, but it would be good to get an official response.
b. Is there a way to force the cache to be cleaned up?  We thought that unloading the library would cause it to clear the cache but it doesn't.
c. Has any memory related fixes gone into ChartDirectory between current production and the version we are using?

We don't want to have to fork a short-lived process just to create the chart.  Point b. above is our preferred option.

Regards, Mohamed

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Mohamed Bana on Sep-21-2012 22:39
Peter, I would also like to know why Valgrind reports an invalid memory read on the call to `textBox->getHeight()` in this code snippet below:

824. int GraphVisualiser::getXAxisLabelHeight()
825. {
826. // ..
827. XYChart labelSizeChart(0, 0);
828.
829. // ...
830. const char* formattedXAxisLabel = labelSizeChart.formatValue(Chart::chartTime2(0), xAxisLabelFormat_.c_str());
831.
832. // ...
833. TextBox* textBox = labelSizeChart.addText(
834.                        0, 0, formattedXAxisLabel, "arialbd.ttf", 8_, 0, Chart::TopLeft, 45);
835.
836. return textBox->getHeight();
837. }

`xAxisLabelFormat_` above is either of the two below:

    xAxisLabelFormat_ = "{value|hh:nn\\ndd-mmm-yy}";
    xAxisLabelFormat_ = "{value|dd-mmm-yy}";

Full stack-trace:

==00:00:02:42.643 16891== Conditional jump or move depends on uninitialised value(s)
==00:00:02:42.643 16891==    at 0x41BB624: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.643 16891==    by 0x450E5FB: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.643 16891==    by 0x4507159: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.643 16891==    by 0x4502DC1: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x44FF575: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x41BAC43: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x4473CD7: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x4193C6B: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x4194C04: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x417F527: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x88317E7: Box::getHeight() const (chartdir.h:691)
==00:00:02:42.644 16891==    by 0x882F9BF: Geneos::ExpressReports::GraphVisualiser::getXAxisLabelHeight() (GraphVisualiser.cpp:836)
==00:00:02:42.644 16891==    by 0x882F792: Geneos::ExpressReports::GraphVisualiser::calculateChartDimensions() (GraphVisualiser.cpp:795)
==00:00:02:42.644 16891==    by 0x882BCB4: Geneos::ExpressReports::GraphVisualiser::visualise(String const&) (GraphVisualiser.cpp:163)
==00:00:02:42.644 16891==    by 0x887C080: Geneos::ExpressReports::TrendReport::generateGraphHtml(String const&, String const&, String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, int, Geneos::ExpressReports::HtmlFragment&) (TrendReport.cpp:2374)
==00:00:02:42.644 16891==    by 0x88783BC: Geneos::ExpressReports::TrendReport::generateReportByManagedVariable(String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, Vector&) (TrendReport.cpp:1822)
==00:00:02:42.644 16891==    by 0x8870E9A: Geneos::ExpressReports::TrendReport::build() (TrendReport.cpp:672)
==00:00:02:42.644 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.644 16891==    by 0x8848EFF: Geneos::ExpressReports::ReportRun::build() (ReportRun.cpp:147)
==00:00:02:42.644 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.644 16891==    by 0x88068D5: reportRunner (ExpressReportsManager.cpp:524)
==00:00:02:42.644 16891==    by 0x45EB96D: start_thread (pthread_create.c:300)
==00:00:02:42.644 16891==    by 0x4871A4D: clone (clone.S:130)
==00:00:02:42.644 16891==  Uninitialised value was created by a heap allocation
==00:00:02:42.644 16891==    at 0x4027444: malloc (vg_replace_malloc.c:263)
==00:00:02:42.644 16891==    by 0x422818C: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x443B136: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x443B045: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x443B236: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x4178E05: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x43DFA53: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x419F6DC: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x4181E17: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.644 16891==    by 0x88327D8: XYChart::XYChart(int, int, int, int, int) (chartdir.h:1862)
==00:00:02:42.644 16891==    by 0x882F902: Geneos::ExpressReports::GraphVisualiser::getXAxisLabelHeight() (GraphVisualiser.cpp:827)
==00:00:02:42.644 16891==    by 0x882F792: Geneos::ExpressReports::GraphVisualiser::calculateChartDimensions() (GraphVisualiser.cpp:795)
==00:00:02:42.644 16891==    by 0x882BCB4: Geneos::ExpressReports::GraphVisualiser::visualise(String const&) (GraphVisualiser.cpp:163)
==00:00:02:42.644 16891==    by 0x887C080: Geneos::ExpressReports::TrendReport::generateGraphHtml(String const&, String const&, String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, int, Geneos::ExpressReports::HtmlFragment&) (TrendReport.cpp:2374)
==00:00:02:42.644 16891==    by 0x88783BC: Geneos::ExpressReports::TrendReport::generateReportByManagedVariable(String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, Vector&) (TrendReport.cpp:1822)
==00:00:02:42.644 16891==    by 0x8870E9A: Geneos::ExpressReports::TrendReport::build() (TrendReport.cpp:672)
==00:00:02:42.644 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.644 16891==    by 0x8848EFF: Geneos::ExpressReports::ReportRun::build() (ReportRun.cpp:147)
==00:00:02:42.644 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.644 16891==    by 0x88068D5: reportRunner (ExpressReportsManager.cpp:524)
==00:00:02:42.644 16891==    by 0x45EB96D: start_thread (pthread_create.c:300)
==00:00:02:42.644 16891==    by 0x4871A4D: clone (clone.S:130)



After this I see a lot of traces like below.  I get invalid reads and invalid writes.



==00:00:02:42.902 16891== Invalid write of size 4
==00:00:02:42.902 16891==    at 0x4207A24: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4207D5B: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x42082F2: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41EEDD2: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x420869C: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x420889D: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4208F33: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4209008: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41F1893: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41F18FB: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41BBCBA: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x45063E0: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41B99A1: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41B9923: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4502DF5: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x44FF575: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x41BAC43: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4473CD7: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4193C6B: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x4194C04: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x417F527: ??? (in /home/dev/Desktop/pebls/EXR-228/gw/trunk/gateway2.linux.RA-120906/lib/libchartdir.so.5.0)
==00:00:02:42.903 16891==    by 0x88317E7: Box::getHeight() const (chartdir.h:691)
==00:00:02:42.903 16891==    by 0x882F9BF: Geneos::ExpressReports::GraphVisualiser::getXAxisLabelHeight() (GraphVisualiser.cpp:836)
==00:00:02:42.903 16891==    by 0x882F792: Geneos::ExpressReports::GraphVisualiser::calculateChartDimensions() (GraphVisualiser.cpp:795)
==00:00:02:42.903 16891==    by 0x882BCB4: Geneos::ExpressReports::GraphVisualiser::visualise(String const&) (GraphVisualiser.cpp:163)
==00:00:02:42.903 16891==    by 0x887C080: Geneos::ExpressReports::TrendReport::generateGraphHtml(String const&, String const&, String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, int, Geneos::ExpressReports::HtmlFragment&) (TrendReport.cpp:2374)
==00:00:02:42.903 16891==    by 0x88783BC: Geneos::ExpressReports::TrendReport::generateReportByManagedVariable(String const&, String const&, VectorMap const&, Geneos::ExpressReports::HtmlFragment&, Vector&, Vector&) (TrendReport.cpp:1822)
==00:00:02:42.903 16891==    by 0x8870E9A: Geneos::ExpressReports::TrendReport::build() (TrendReport.cpp:672)
==00:00:02:42.903 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.903 16891==    by 0x8848EFF: Geneos::ExpressReports::ReportRun::build() (ReportRun.cpp:147)
==00:00:02:42.903 16891==    by 0x8843AEB: Geneos::ExpressReports::ReportingComponent::build(String const&, String const&) (ReportingComponent.cpp:12)
==00:00:02:42.903 16891==    by 0x88068D5: reportRunner (ExpressReportsManager.cpp:524)
==00:00:02:42.903 16891==    by 0x45EB96D: start_thread (pthread_create.c:300)
==00:00:02:42.903 16891==    by 0x4871A4D: clone (clone.S:130)
==00:00:02:42.903 16891==  Address 0xb82602c is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes



Thank you and have a nice weekend,
Mohamed

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Mohamed Bana on Sep-21-2012 23:14
Sorry about all the questions.

Is it possible to capture all the values passed to the XYChart so I that I can write a sample program to illustrate the memory usage?  Some way to dump the the XYChart structure that a typical run of our application would generate?

Thank you,
Mohamed

  Re: Is memory released when you unload libchartdir.so in your program?
Posted by Peter Kwan on Sep-22-2012 03:21
Hi Mahamed,

(a) As a computer graphics software, using a few MB of memory is not abnormal.

ChartDirector may need around 10 bytes per pixel at its peak to render the chart. So if your chart is 1000 x 1000, it may use 10 MB of memory just for rendering, while if you chart is 300 x 200, it may use 600K only. These memory will be released after the chart object is deleted. (So it is just a temporary memory usage, not permanent.)

If your code creates image map (using getHTMLImageMap), it can take in the order of  200 bytes per hot spot (it depends on how long is your tooltip, etc). If you have tens of thousands of points, the hot spots can consume a few MB. Again, the memory is released when the chart object is deleted.

Note that your code may copy the image map to a String variable, in which case your own variable will also consume the same memory as the image map.

Apart from the above, there will also be memory used to copy your data, including the numbers and text strings. The exact amount depends on the amount of data you have. All these memory will be released when the chart object is deleted.

Internally, ChartDirector will keep a cache for fonts. Rendering text is resource intensive (it needs to open a font file, look up the glyph definition, and render it to the size your code specify, etc). Luckily, the charts usually just repeatedly used similar characters, so it is feasible to cache the glyphs. I believe ChartDirector currently used a timeout system to clear the cache. (If the fonts or glyphs are not used for a certain period, they will be flushed from cache the next time ChartDirector has a chance to run.) Note that a font file can be less than 400 KB for the normal Arial font to 23MB for the Arial Unicode font.

(b) Normally the font cache would not be totally empty except during start up. It is because to clear old cache, ChartDirector needs to run. ChartDirector runs only if your code calls its API, which probably means your code is creating a chart. So fonts are needed and the fonts will be cached if they are not already cached.

As mentioned in my previous message, ChartDirector does release the cache when the program shuts down. But whether Valgrind is able to properly measure it is another matter.

Actually, I have tested the code using Valgrind as well. I tried to "./configure" and compile the latest Valgrind on our build system, and it comes up with the error message that our compiler is not supported by Valgrind. Eventually, I do find a Valgrind that can support our compiler, and it does not report any leak in our program. I have also tried to run our compiled code in another computer that does support the latest Valgrind. Apart from reporting leaks (which are not really leaks as they are not increasing indefinitely), it also generates a lot of other error messages (such as unable to understand some sections of the code, and other errors similar to the one your have reported).

In fact, if you look at your error messages, the last line says "To suppress, use: --workaround-gcc296-bugs=yes". It means Valgrind knew what is considered as "error" may be normal code generated by some compiler. From my understanding, Valgrind has an internal database that can help it to determine if it an actual error, or if it is the normal code generated by the compiler. But Valgrind version you are using probably does not know the compiler we are using.

(c) There is no memory related fix gone into ChartDirectory between the latest version and the version you are using.

In my opinion, you do not need to fork a short-lived process to create the chart, as the memory usage is not increasing, and in my opinion, it is not high for a computer graphics program. I believe ChartDirector will not use 10MB for cache (unless you are using large font files for international text, in which case font caching will be a huge benefit), but ChartDirector can use 10MB for rendering the chart depending on the number of pixels. The latter memory will be deleted when the chart object is deleted. Even if you fork a process, you would still need the 10MB to render a chart, and it probably uses even more memory due to forking overhead.

Usually there is no automatic method in ChartDirector to "capture" all the values passed to an XYChart, and there is no method to "dump" the XYChart structure (as computer graphics strutures are very complicated).

Regards
Peter Kwan