[geos-devel] Potential memory leak in GEOSTopologyPreserveSimplify

Bill Zissimopoulos geos at billz.fastmail.fm
Mon Jan 28 05:01:24 EST 2008


Hello:

I wish to report a potential memory leak in
GEOSTopologyPreserveSimplify. This memory leak appears serious enough
that my batch processing software will run out of memory a few minutes
into its processing.

This is with geos-3.0.0 on Mac OS X 10.4.11. The library has been
configured and made without any special options:
	./configure --prefix=<somedir>/.install; make; make install

I have modified the capi/geostest.c program to demonstrate the problem.
The file is included at the end of this mail. I have used standard Mac
OS X tools to track the memory leak:
	MallocStackLogging=1 ./a.out test.wkt
Using Mac OS X's /usr/bin/leaks tool and after some post-processing I
get as output the call stacks of the allocation point of leaked objects.
This output is included at the end of this mail.

Looking at the output it appears that (among others)
geos::index::quadtree::Node::NodeBase objects get created but never
freed. My knowledge of the GEOS internals is 0, so I am turning to this
list in the hope that the matter can be resolved.

Many thanks for your help and attention. Please note that I am not
subscribed to the geos-devel list so CC me on any responses.

Bill


leaks:
<<
start | _start | main | do_all | GEOSTopologyPreserveSimplify |
geos::simplify::TopologyPreservingSimplifier::simplify(geos::geom::Geometry
const*, double) |
geos::simplify::TopologyPreservingSimplifier::getResultGeometry() |
geos::simplify::LineSegmentIndex::add(geos::simplify::TaggedLineString
const&) | geos::simplify::LineSegmentIndex::add(geos::geom::LineSegment
const*) | geos::index::quadtree::Quadtree::insert(geos::geom::Envelope
const*, void*) |
geos::index::quadtree::Root::insert(geos::geom::Envelope const*, void*)
| geos::index::quadtree::NodeBase::add(void*) | std::vector<void*,
std::allocator<void*>
>::_M_insert_aux(__gnu_cxx::__normal_iterator<void**, std::vector<void*,
std::allocator<void*> > >, void* const&) | operator new(unsigned long) |
malloc

start | _start | main | do_all | GEOSTopologyPreserveSimplify |
geos::simplify::TopologyPreservingSimplifier::simplify(geos::geom::Geometry
const*, double) |
geos::simplify::TopologyPreservingSimplifier::getResultGeometry() |
geos::simplify::LineSegmentIndex::add(geos::simplify::TaggedLineString
const&) | geos::simplify::LineSegmentIndex::add(geos::geom::LineSegment
const*) | geos::index::quadtree::Quadtree::insert(geos::geom::Envelope
const*, void*) |
geos::index::quadtree::Root::insert(geos::geom::Envelope const*, void*)
|
geos::index::quadtree::Root::insertContained(geos::index::quadtree::Node*,
geos::geom::Envelope const*, void*) |
geos::index::quadtree::Node::getNode(geos::geom::Envelope const*) |
geos::index::quadtree::Node::getSubnode(int) |
geos::index::quadtree::Node::createSubnode(int) |
geos::index::quadtree::NodeBase::NodeBase[not-in-charge]() | operator
new(unsigned long) | malloc

start | _start | main | do_all | GEOSTopologyPreserveSimplify |
geos::simplify::TopologyPreservingSimplifier::simplify(geos::geom::Geometry
const*, double) |
geos::simplify::TopologyPreservingSimplifier::getResultGeometry() |
geos::simplify::LineSegmentIndex::add(geos::simplify::TaggedLineString
const&) | geos::simplify::LineSegmentIndex::add(geos::geom::LineSegment
const*) | geos::index::quadtree::Quadtree::insert(geos::geom::Envelope
const*, void*) |
geos::index::quadtree::Root::insert(geos::geom::Envelope const*, void*)
|
geos::index::quadtree::Root::insertContained(geos::index::quadtree::Node*,
geos::geom::Envelope const*, void*) |
geos::index::quadtree::Node::getNode(geos::geom::Envelope const*) |
geos::index::quadtree::Node::getSubnode(int) |
geos::index::quadtree::Node::createSubnode(int) | operator new(unsigned
long) | malloc

start | _start | main | do_all | GEOSTopologyPreserveSimplify |
geos::simplify::TopologyPreservingSimplifier::simplify(geos::geom::Geometry
const*, double) |
geos::simplify::TopologyPreservingSimplifier::getResultGeometry() |
geos::simplify::TaggedLineStringSimplifier::simplify(geos::simplify::TaggedLineString*)
| geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::hasBadIntersection(geos::simplify::TaggedLineString
const*, std::vector<unsigned long, std::allocator<unsigned long> >
const&, geos::geom::LineSegment const&) |
geos::simplify::TaggedLineStringSimplifier::hasBadInputIntersection(geos::simplify::TaggedLineString
const*, std::vector<unsigned long, std::allocator<unsigned long> >
const&, geos::geom::LineSegment const&) |
geos::simplify::LineSegmentIndex::query(geos::geom::LineSegment const*)
const | geos::index::quadtree::NodeBase::visit(geos::geom::Envelope
const*, geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visit(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::index::quadtree::NodeBase::visitItems(geos::geom::Envelope const*,
geos::index::ItemVisitor&) |
geos::simplify::LineSegmentVisitor::visitItem(void*) |
std::vector<geos::geom::LineSegment*,
std::allocator<geos::geom::LineSegment*>
>::_M_insert_aux(__gnu_cxx::__normal_iterator<geos::geom::LineSegment**,
std::vector<geos::geom::LineSegment*,
std::allocator<geos::geom::LineSegment*> > >, geos::geom::LineSegment*
const&) | operator new(unsigned long) | malloc

start | _start | main | do_all | GEOSTopologyPreserveSimplify |
geos::simplify::TopologyPreservingSimplifier::simplify(geos::geom::Geometry
const*, double) |
geos::simplify::TopologyPreservingSimplifier::getResultGeometry() |
geos::simplify::TaggedLineStringSimplifier::simplify(geos::simplify::TaggedLineString*)
| geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::simplifySection(unsigned
long, unsigned long, unsigned long) |
geos::simplify::TaggedLineStringSimplifier::flatten(unsigned long,
unsigned long) |
geos::simplify::TaggedLineStringSimplifier::remove(geos::simplify::TaggedLineString
const*, unsigned long, unsigned long) |
geos::simplify::LineSegmentIndex::remove(geos::geom::LineSegment const*)
| geos::index::quadtree::Quadtree::remove(geos::geom::Envelope const*,
void*) |
geos::index::quadtree::Quadtree::ensureExtent(geos::geom::Envelope
const*, double) | operator new(unsigned long) | malloc
>>

modified geostest.c:
<<
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "geos_c.h"

#define MAXWKTLEN 1047551

void
usage(char *me)
{
	fprintf(stderr, "Usage: %s <wktfile>\n", me);
	exit(1);
}

void
notice(const char *fmt, ...) {
	va_list ap;

        fprintf( stdout, "NOTICE: ");

	va_start (ap, fmt);
        vfprintf( stdout, fmt, ap);
        va_end(ap);
        fprintf( stdout, "\n" );
}

void
log_and_exit(const char *fmt, ...) {
	va_list ap;

        fprintf( stdout, "ERROR: ");

	va_start (ap, fmt);
        vfprintf( stdout, fmt, ap);
        va_end(ap);
        fprintf( stdout, "\n" );
	exit(1);
}

int
do_all(char *inputfile)
{
	GEOSGeometry* g1;
	GEOSGeometry* g2;
	static char wkt[MAXWKTLEN];
	FILE *input;
	char *ptr;
	unsigned char* uptr;
	size_t size;
    int i;

	input = fopen(inputfile, "r");
	if ( ! input ) { perror("fopen"); exit(1); }

	size = fread(wkt, 1, MAXWKTLEN-1, input);
	fclose(input);
	if ( ! size ) { perror("fread"); exit(1); }
	if ( size == MAXWKTLEN-1 ) { perror("WKT input too big!"); exit(1); }
	wkt[size] = '\0'; /* ensure it is null terminated */

	g1 = GEOSGeomFromWKT(wkt);

#if 0
	/* Simplify */
    for (i = 0; i < 100000; i++)
    {
    	g2 = GEOSSimplify(g1, 0.5);
    	GEOSGeom_destroy(g2);
    	putc('s', stderr); fflush(stderr);
    }
#endif

#if 1
	/* Topology Preserve Simplify */
    for (i = 0; i < 100000; i++)
    {
    	g2 = GEOSTopologyPreserveSimplify(g1, 0.5);
    	GEOSGeom_destroy(g2);
    	putc('t', stderr); fflush(stderr);
    }
#endif

	GEOSGeom_destroy(g1);
	
    getc(stdin);

	return 0;
}

int
main(int argc, char **argv)
{
	int i, n=1;

	initGEOS(notice, log_and_exit);
	printf("GEOS version %s\n", GEOSversion());

	if ( argc < 2 ) usage(argv[0]);
	if ( argc > 2 ) n=atoi(argv[2]);
	if ( ! n ) n=1;

	for (i=0; i<n; i++) {
		do_all(argv[1]);
	}
	putc('\n', stderr);

	finishGEOS();

	return EXIT_SUCCESS;
}
>>


More information about the geos-devel mailing list