dahlia/wand — pull request #62 by mlindgren (2012-09-30 23:25:50+00:00)
Title: Fixed several memory leaks

I found and fixed more than 10 memory leaks in Wand in this patch. Specifically:

- There was a circular reference between the `Image` and `Metadata` classes. [Python cannot garbage collect circular references on classes which have explicit destructors](http://docs.python.org/library/gc.html#gc.garbage), so this meant that `Image`s were never freed. I fixed this by changing the reference from `Metadata` to its parent `Image` to a `weakref`.

Without patch:
```
>>> from wand.image import Image
>>> import gc
>>> def f():
... img = Image(filename='/Users/mitch/Pictures/mitch_kh.jpg')
...
>>> for i in range(10): f()
...
>>> gc.collect()
40
>>> gc.garbage
[, , , , , , ,
, , ]
```

With patch:
```
>>> from wand.image import Image
>>> import gc
>>> def f():
... img = Image(filename='/Users/mitch/Pictures/mitch_kh.jpg')
...
>>> for i in range(10): f()
...
>>> gc.collect()
0
>>> gc.garbage
[]
```
- The setter for `Resource` did not destroy the previous `c_resource`, if any existed, which caused resources to be leaked when an `Image`'s `wand` property was changed after creation.
- Almost all of the `ctypes` functions in api.py returning `c_char_p`s leaked, because `c_char_p`s are automatically converted to Python strings and the original pointer is discarded, making it impossible to free the C string with `MagickRelinquishMemory`. I fixed this by subclassing `c_char_p` to avoid the automatic conversion and accesing `.value` in places where the string values were previously used, and calling `MagickRelinquishMemory` in `c_magick_char_p`'s destructor.

`GetMagickVersion` and `GetMagickReleaseDate` didn't need to be changed because they return const strings.

I ran the tests with these changes on Windows 7 x64, CentOS 6.3 x64 and OS X Mountain Lion x64. I also did some impromptu memory testing by creating images and performing operations on them in a loop which ran hundreds of times. I think I've gotten rid of all of the leaks but it's hard to be sure because I don't know of a good tool to find `ctypes` leaks.

I did not change the version number—I'll leave that up to you, but I would strongly recommend releasing this patch before version 3.0 as some of the leaks I fixed can very quickly lead to Python consuming all of a machine's RAM. I noticed the problem at first when the web app I'm developing was using 2GB of RAM after I uploaded some photos. :)