1

I have a small AppleScriptObjC app that I use for processing photos. I need to fix a memory leak that I've discovered which seems to be caused by the photos being cached and not being released. This occurs every time I process (initWithContentsOfFile_) which causes the memory usage to increase with each process. The relevant section of my code is:

on applicationWillFinishLaunching_(aNotification)
    set inputPath to (choose folder with prompt "Select The Input Directory" default location (path to desktop folder))
    tell application "finder"
    set imageNames to get name of files of inputPath
    end tell
    set imagesRemaining to (number of items of imageNames) as string
    my errorAlert(imagesRemaining & " photos remaining.")
    if (number of items of imageNames) = 0
    my errorAlert("There are no items in the directory.")
    else
    set numberOfImages to number of items of imageNames
    set currentPath to inputPath & (item 1 of imageNames) as string
    set theImage to initWithContentsOfFile_(POSIX path of currentPath) of alloc() of class "NSImage" of current application
    setImage_(theImage) of imageView
    set theImage to missing value
end if
end applicationWillFinishLaunching_

This part of the script assigns the first photo, the other processing functions are pretty much identical.

I'm either trying to figure out how to correctly release each photo or, alternatively, use the setCacheMode:NSImageCacheNever to disable the caching function. Despite trying for a long time to figure out the proper syntax in ApplescriptObjC, I can't seem to fix the memory leak. Thanks!

For reference, here's the button action which causes the memory to increase every time executed:

    on photoOutput1_(sender)
        if output1 = ""
        set output1 to (choose folder with prompt "Select The Output Path #1" default location (path to desktop folder))
        else
    end if
tell application "Finder"
set ProcessedPhoto to quoted form of (POSIX path of CurrentPath)
set photoNumber to photoNumber + 1
set DateAppend to do shell script "date +%m-%d_%H.%M"
set DateAppend to DateAppend & "_" & photoNumber
set OutputPath to quoted form of ((POSIX path of output1) & DateAppend & ".jpg")
try
    do shell script "mv -n " & ProcessedPhoto & " " & OutputPath
    on error
    my errorAlert("Unable to move the photo. Please try again.")
    return
end try
            set imageNames to get name of files of inputPath
        end tell
set imagesRemaining to (number of items of imageNames) as string
my errorAlert(imagesRemaining & " photos remaining.")
        if (number of items of imageNames) = 0
        imageView's setImage_(missing value)
        my errorAlert("There are no more photos in the directory.")
        else
        set numberOfImages to number of items of imageNames
        set currentPath to inputPath & (item 1 of imageNames) as string
set theImage to missing value
imageView's setImage_(theImage)
set theImage to initWithContentsOfFile_(POSIX path of currentPath) of alloc() of class "NSImage" of current application
        setImage_(theImage) of imageView
tell application "Finder"
        set OutputImageNames to number of files in folder output1
        end tell
        buttonA's setTitle_("A (" & OutputImageNames & ")")
        end if
    end photoOutput1_
Cornelius Qualley
  • 721
  • 5
  • 10
  • 19
  • Probably duplicate of http://stackoverflow.com/questions/38255556/nsimage-release-in-applescriptobjc – matt Apr 01 '17 at 02:52
  • You're right, it is almost a duplicate, however that solution didn't actually solve the memory issue as indicated in the comments. I read that question before posting this one. – Cornelius Qualley Apr 01 '17 at 03:29
  • But the point is that asking the same thing again won't magically change anything. – matt Apr 01 '17 at 04:16
  • I posted because the question isn't solved...and it's 8 months old. I've offered another possible solution (setCacheMode) which was not previously discussed. Unfortunately, I don't know how to utilize that function in ApplescriptObjC, maybe someone else does. I don't think that this is simply a shortcoming of Applescript, I think there just needs to be the correct approach, which hopefully someone has. – Cornelius Qualley Apr 01 '17 at 04:36
  • The cache mode is irrelevant. It's not that kind of cache. It has to do with drawing, not memory management. – matt Apr 01 '17 at 12:03
  • I see a similar problem using NSAutoreleasePool in this article: http://stackoverflow.com/questions/5047682/memory-continues-to-increase-when-loading-and-releasing-nsimage. Is that possible to replicate in ApplescriptObjC? I'm getting "cannot retain an autorelease pool" error in my attempt to implement it. – Cornelius Qualley Apr 01 '17 at 17:10
  • Yes, I saw that, but I didn't link you to it because you can't make an autorelease pool in AppleScript — plus it didn't solve the problem. – matt Apr 01 '17 at 17:19

1 Answers1

1

You may try to both release the image variable and the image because in Applescript the contents are copied and not pointers:

set theImage to missing value
imageView's setImage_(theImage)

Also check twice that there's nothing else causing your leaks. Did you use instruments? Check the allocations

Pat_Morita
  • 3,355
  • 3
  • 25
  • 36
  • Thanks, but I'm getting the same behavior. I've tried every possible way I can think of to release the images. I checked Instruments and I'm seeing a allocation for each instance of the image for: ImageIO (jpeg_data), Foundation (Malloc), and CoreGraphics (GSImageData). Foundation and ImageIO are about the size of each image and CoreGraphics is about half the size. – Cornelius Qualley Apr 02 '17 at 16:21
  • I posted the full launch function, I can definitely post more but the entire script is kind of long. Hopefully that helps. – Cornelius Qualley Apr 02 '17 at 20:43
  • I cannot see a loop..?.you said "everytime I process" ... this method is executed once when application is almost loaded. Is this not the right context? – Pat_Morita Apr 02 '17 at 20:55
  • So, that loads an initial photo, then every time a button is pressed to process a photo, the memory increases by the size of the photo. I've updated my question with that portion of the code. Hopefully that helps. – Cornelius Qualley Apr 03 '17 at 04:15
  • Do you have a property set for theImage? – Pat_Morita Apr 03 '17 at 05:09
  • I don't currently, although I've tried setting "property theImage : missing value" and it seemed to have no effect either way. – Cornelius Qualley Apr 03 '17 at 13:53
  • Phew... your code likes fine though. Your syntax is technically correct applescript but hard to read. It's more readable if your write it like this instead using "of" mutliple times. "set theImage to current application's NSImage's alloc()'s initWithContentsOfFile:thePath" But for your question i cannot find anything wrong with your code. Maybe it's just applescript's memory management. – Pat_Morita Apr 03 '17 at 14:03
  • Yeah, that's what I was afraid of, I probably just need to rewrite it in a different language. And, I know the code is pretty dirty, I just kept tacking on different parts on the script, it could definitely be a lot cleaner. Thanks anyway! – Cornelius Qualley Apr 03 '17 at 14:51