[Openmcl-devel] Fix memory leak in an objc example

Paul Krueger plkrueger at comcast.net
Sat May 3 07:54:58 PDT 2014


A couple of clarifications ……

First, I presume that you understand the distinction between creating a pointer with an rlet and creating an immediate object structure. Not all objective-c objects are represented with pointers in lisp. There are several things like NSInteger, NSPoint, NSRange, NSRect, and others that are just direct structures. So if you create those in an rlet you wouldn't release them later since the memory for them is allocated on the stack and reclaimed when the rlet form exits. You will get an error if you try to do this because the object you are trying to release is not a pointer, so you'll immediately know that you did something wrong.
 
More subtle problems would occur if you released objects that are returned by what are called  "convenience constructors" by Apple (presumably because you don't have to worry about managing their memory). These constructors return objective-c objects which are already autoreleased. If you already know about these, then you'll be fine; just don't release such objects. 

If you're not familiar with convenience constructors then I'd suggest that you do some reading. The apple documentation is not always very clear about which constructors are of this form and which are not, but read the doc anyway since it will sometimes be helpful. If you google "apple convenience constructor" you will find all sorts of information about them which may help you. If you release an object created via a convenience constructor, you can cause all sorts of problems since the memory may be reused and then released by the autorelease prematurely. Trust me, such problems can be difficult to diagnose.

On May 3, 2014, at 2:09 AM, Leo Liu <sdl.web at gmail.com> wrote:

> On 2014-04-30 21:48 -0400, R. Matthew Emerson wrote:
>> You're confusing unrelated things.
>> 
>> What rlet does is to allocate some memory on the stack.
>> 
>> According to Apple's conventions, because _LSCopyAllApplicationURLs
>> has the word "copy" in it, you "own" whatever it returns, and must
>> release it when you're done with it.
>> 
>> So, you might say
>> (let ((array (%get-ptr urls)))
>>  ;; use array
>>  (#/release array) ;or (#_CFRelease array)
>> 
>> The main difference between #/release and #_CFRelease is that the
>> call to #_CFRelease will crash if you pass it a null pointer (as
>> made by (ccl:%null-ptr) or +null-ptr+), and #/release won't.  As with
>> all Objective-C methods, sending a message to a null pointer returns
>> a null pointer.
> 
> Thank you rme for the help here and on #irc.
> 
> It seems I need to release every object that is placed in rlet's
> pointers.
> 
> For example (full file attached):
> 
> (defun default-application (url)
>  (objc:with-autorelease-pool
>    (ccl:rlet ((appurl #>CFURLRef))
>      (let* ((url (#/fileURLWithPath: ns:ns-url
>                                      (ccl:with-encoded-cstrs :utf-8 ((s url))
>                                        (#/stringWithUTF8String: ns:ns-string s))))
>             (status (#_LSGetApplicationForURL
>                      url #$kLSRolesAll ccl:+null-ptr+ appurl)))
>        (when (zerop status)
>          (nsurl-to-path (ccl:%get-ptr appurl)))))))
> 
> (progn (loop repeat 10000 do (default-application "/Applications/Contacts.app")) (ccl:gc))
> 
> Will increase the memory use by a few megabytes.
> 
> Leo
> 
> <memleak.lisp>_______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://lists.clozure.com/mailman/listinfo/openmcl-devel




More information about the Openmcl-devel mailing list