[Pyrex] Serious memory leak in a simple extension type

Jonathan Doda jdoda at sympatico.ca
Thu Jul 21 15:08:14 CEST 2005


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello.  I was hoping someone on this list would be able to help me
figure out why my extension type is leaking.  I've attached the
extension type, and a simple test case.  The test case will fairly
quickly consume all the memory on my computer, but if I import my
original pure python class instead of the pyrex extension type memory
consumption remains steady at about 2.2 MB.

I'm running Ubuntu 5.04 on x86, with Pyrex 0.9.3, gcc 3.3.5 and Python
2.4.1.

Thanks for your time.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)

iD8DBQFC354+WEgeeLQ8a74RAryCAJ9M6UoLn8NFQfM+T59dZYJLmzSTmwCg6Wvz
zAoJc3pkod5ZcgFqGV1slw4=
=ivbZ
-----END PGP SIGNATURE-----
-------------- next part --------------
#Copyright (c) 2004-2005 Jonathan Doda
#
#Permission is hereby granted, free of charge, to any person obtaining a 
#copy of this software and associated documentation files (the "Software"), 
#to deal in the Software without restriction, including without limitation 
#the rights to use, copy, modify, merge, publish, distribute, sublicense, 
#and/or sell copies of the Software, and to permit persons to whom the 
#Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in 
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
#THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
#OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
#SOFTWARE.

cdef extern from "math.h":
    double M_PI
    double sin(double x)
    double cos(double x)
    double atan2(double y, double x)
    double sqrt(double x)
    double pow(double x, double y)

cdef class Vector:
    """A vector class implementing a limited set of arithmatic operations.

    The operators implemented are +, -, *, /, the abs() function and the ==
    comparison. + and - operate on a pair of vectors.  * and / operate on a
    vector and a scalar.  * can also operate on two vectors, in which case it
    returns the dot product.  The == comparison operates on a pair of vectors.

    The internal representation of a vector is as x an y components, and all
    operators act on these components.  Vectors provide magnitude and direction
    properties which can be modified directly, but this is very slow compared to
    acting on the components, and should therefore be avoided whenever possible.
    """

    cdef public double x, y

    def __init__(self, double x=0, double y=0):
        """Set initial components.  Defaults to the zero vector.
        """
        
        self.x = x
        self.y = y

    def __repr__(self):
        return '<vector x=%s y=%s mag=%s dir=%s>' % (self.x,
                                                      self.y,
                                                      self.magnitude,
                                                      self.direction)
        
    def __add__(self, other):
        return self.add(other)

    def __sub__(self, other):
        return self.subtract(other)

    def __mul__(self, other):
        if isinstance(self, Vector):
            
            if isinstance(other, Vector):
                return self.dot(other)
            else:
                return self.multiply(other)
        
        if isinstance(other, Vector):
            return other.multiply(self)

    def __div__(self, other):
        if isinstance(self, Vector):
            return self.divide(other)
        elif isinstance(other, Vector):
            return other.divide(self)
        
    def __truediv__(self, other):
        if isinstance(self, Vector):
            return self.divide(other)
        elif isinstance(other, Vector):
            return other.divide(self)

    def __abs__(self):
        return self.magnitude

    def __richcmp__(self, other, op):
        return self.compare(other, op)

    def add(self, other):
        return self._add(other)

    cdef Vector _add(self, Vector other):
        return Vector(self.x + other.x, self.y + other.y)

    def subtract(self, other):
        return self._subtract(other)

    cdef Vector _subtract(self, Vector other):
        return Vector(self.x - other.x, self.y - other.y)       

    def multiply(self, other):
        return self._multiply(other)

    cdef Vector _multiply(self, double other):
        return Vector(self.x * other, self.y * other)
        
    def dot(self, other):
        return self._dot(other)

    cdef double _dot(self, Vector other):
        return (self.x * other.x) + (self.y * other.y)        

    def divide(self, other):
        return self._divide(other)

    cdef Vector _divide(self, double other):
        return Vector(self.x / other, self.y / other)

    def compare(self, other, op):
        return self._compare(other, op)

    cdef object _compare(self, Vector other, int op):
        if op == 2:
            if self.x != other.x:
                return False
            if self.y != other.y:
                return False
            return True
        else:
            return NotImplemented

    def project(self, other):
        """Return the projection of self on other.
        """
        return self._project(other)

    cdef Vector _project(self, Vector other):
        cdef Vector projection
        projection = Vector(other.x, other.y)
        projection._set_magnitude(self._component(other))
        return projection
        
    def component(self, other):
        """Return the component of self on other.
        """
        return self._component(other)

    cdef double _component(self, Vector other):
        return self._dot(other) / other._get_magnitude()

    property magnitude:
        
        def __get__(self):
            return self._get_magnitude()

        def __set__(self, magnitude):
            self._set_magnitude(magnitude)

        def __del__(self):
            pass

    cdef double _get_magnitude(self):
        return sqrt(pow(self.x, 2) + pow(self.y, 2))

    cdef void _set_magnitude(self, double magnitude):
        cdef double magnitude_ratio
        magnitude_ratio = magnitude / self._get_magnitude()
        self.x = self.x * magnitude_ratio
        self.y = self.y * magnitude_ratio

    property direction:
        
        def __get__(self):
            return self._get_direction()

        def __set__(self, direction):
            self._set_direction(direction)

        def __del__(self):
            pass

    cdef double _get_direction(self):
        cdef double direction        
        direction = atan2(self.y, self.x)
        if direction < 0:
            direction = direction + (M_PI * 2)
        return direction

    cdef void _set_direction(self, double direction):
        cdef double magnitude
        magnitude = self._get_magnitude()
        self.x = cos(direction) * magnitude
        self.y = sin(direction) * magnitude

-------------- next part --------------
A non-text attachment was scrubbed...
Name: leaktest.py
Type: text/x-python
Size: 75 bytes
Desc: not available
Url : http://lists.copyleft.no/pipermail/pyrex/attachments/20050721/f2d6617c/leaktest.py


More information about the Pyrex mailing list