Stay open applescript leaking memory in OSX 10.8.4

We use three stay open applescripts, that use “On Idle” and “End Idle” in Mountain Lion. Since 10.8, these scripts have been causing a memory leak (Activity Monitor, WindowServer), and if we don’t restart the computer they run on each day, eventually, the computer freezes due to lack of memory. This is a known bug in OSX, but is there another way to keep the script running without having the memory leak issue?
Does anyone else have this issue?

Well, you’re working around a bug, so I suppose you may consider a hack.

Perhaps schedule quitting after a timeout & then an appropriately scheduled relaunch (via iCal?)

Correct, AppleScript isn’t memory-leak-safe. Normally you’ll run a script and close it afterwards, so the leaks won’t grow into something noticable. The way you write your code has some small effects on the memory management but you’re never be able to get all of it out there. So instead of keeping your AppleScript instance open, it’s better to close them and move your interval outside AppleScript.

I always launch my scripts using launchd (lingon is an useful tool that makes managing launchd easier).

Hi Ryan,

There is another way with pmset. It might depend though. What’s the idle time and maybe someother things in the script. Another thing is maybe your script is using up memory with the variables.

Edited: it was launched to run scripts at certain times. I didn’t see DJ Bazzie Wazzies post. It works very well also.

gl,
kel

Are you sure your applet didn’t leak memory in earlier versions of OS X?

If you hope to see it fixed, make sure you log a bug report with Apple.

Here is the script we have, which leaks memory.

property dropboxPath : “Prepress:PDF_4900R” as alias
property epsonproofPath : “Prepress:PDF_4900R:EPSONProof” as alias
property excluded : “Prepress:PDF_4900R:Failed” as alias

–Nutrition
property nutrition : “Catalogs:Catalog Production:CATALOGS:1076_2014_Nutrition:Final PDF Files:Approved Regular Version” as alias
–International Healthcare
property ihc : “Catalogs:Catalog Production:CATALOGS:1073_2014_IntHealthCare:Final PDF Files” as alias
–Physical Education
property physical : “Catalogs:Catalog Production:CATALOGS:1102_2015_PhyEd:Final PDF Files:Approved Regular Version” as alias
–Benton Kirby July
property bkjuly : “Catalogs:Catalog Production:CATALOGS:1087_2015_BentonKirby_July:Final PDF Files” as alias
–Arts and Crafts BTS
property acbts : “Catalogs:Catalog Production:CATALOGS:1077_2014_Arts&Crafts_BTS:Final PDF Files” as alias
–Early Learning
property earlylearning : “Catalogs:Catalog Production:CATALOGS:1107_2015_EarlyLearning:Final PDF Files” as alias

on idle

set dropboxitems to (list folder dropboxPath without invisibles) -- list of names
if dropboxitems is not {} then
	delay 10
	tell application "Finder"
		set folpath to (dropboxPath as text)
		repeat with n in dropboxitems
			try
				set f to (file (folpath & n))
				
				--Nutrition
				if n begins with "14NUT" then
					duplicate f to epsonproofPath
					move f to nutrition with replacing
					delete f
				end if
				--International Healthcare
				if n begins with "14IHC" then
					duplicate f to epsonproofPath
					move f to ihc with replacing
					delete f
				end if
				--Physical Education
				if n begins with "15PEp" then
					duplicate f to epsonproofPath
					move f to physical with replacing
					delete f
				end if
				tell application "Finder"
					set trashCount to count of items of trash
					if trashCount is greater than 9 then
						empty trash
					end if
					--Benton Kirby July
					if n begins with "15BK" then
						duplicate f to epsonproofPath
						move f to bkjuly with replacing
						delete f
					end if
					--Arts and Crafts BTS
					if n begins with "14ACBTS" then
						duplicate f to epsonproofPath
						move f to acbts with replacing
						delete f
					end if
					--Early Learning
					if n begins with "15ELp" then
						duplicate f to epsonproofPath
						move f to earlylearning with replacing
						delete f
					end if
				end tell
				-- 6. moves PDF files that are not listed in the catalog list to a Failed folder and opens that folder window	
				
				move f to excluded with replacing
				display dialog "This PDF wasn't moved to a final destination. It will be located in the Failed folder. Please move this to it's appropriate location." buttons "OK" default button 1
				open folder excluded
				set bounds of container window of folder excluded to {200, 200, 600, 400}
			end try
		end repeat
	end tell
end if

return 5 -- return to this handler after 5 seconds

end idle

Rather than polling a folder with a stay open script I’d recommend to use a folder action or “ still more reliable “ a launchd agent with the WatchPaths key.
The benefit is much less CPU and RAM and no memory leaks because the attached script is not required to stay open

PS: this is a more effective version of your script.
It works with string paths instead of alias specifiers (also to be able to compile it on machines which lack the locations)
It uses lists (prefixList, destinationList) and a repeat loop to process the files.
When a prefix matches and the file has been moved the inner loop is left.
The files are immediately deleted with a shell command.
In case of an error the error message is logged into ~/Library/Logs. The log can be watched in Console.app

However I haven’t tested the script, the environment iss too special


property dropboxPath : "Prepress:PDF_4900R:"
property epsonproofPath : dropboxPath & "EPSONProof:"
property excluded : dropboxPath & "Failed:"

property catalogProductionFolder : "Catalogs:Catalog Production:CATALOGS:"

--Nutrition
property nutrition : catalogProductionFolder & "1076_2014_Nutrition:Final PDF Files:Approved Regular Version:"
--International Healthcare
property ihc : catalogProductionFolder & "1073_2014_IntHealthCare:Final PDF Files:"
--Physical Education
property physical : catalogProductionFolder & "1102_2015_PhyEd:Final PDF Files:Approved Regular Version:"
--Benton Kirby July
property bkjuly : catalogProductionFolder & "1087_2015_BentonKirby_July:Final PDF Files:"
--Arts and Crafts BTS
property acbts : catalogProductionFolder & "1077_2014_Arts&Crafts_BTS:Final PDF Files:"
--Early Learning
property earlylearning : catalogProductionFolder & "1107_2015_EarlyLearning:Final PDF Files:"

property prefixList : {"14NUT", "14IHC", "15PEp", "15BK", "14ACBTS", "15ELp"}
property destinationList : {nutrition, ihc, physical, bkjuly, acbts, earlylearning}

property logName : "DropboxDistributionError.log"

on idle
	
	set dropboxitems to (list folder alias dropboxPath without invisibles) -- list of names
	set initialDelay to true
	
	repeat with anItemName in dropboxitems
		if initialDelay then
			delay 10
			set initialDelay to false
		end if
		try
			set processed to false
			set filePath to dropboxPath & anItemName
			repeat with i from 1 to (count prefixList)
				set namePrefix to item i of prefixList
				set destinationFolder to item i of destinationList
				if anItemName begins with namePrefix then
					tell application "Finder"
						duplicate file filePath to folder epsonproofPath
						move file filePath to folder destinationFolder with replacing
						do shell script "rm " & quoted form of POSIX path of filePath
					end tell
					set processed to true
					exit repeat
				end if
			end repeat
			if not processed then
				tell application "Finder"
					move file filePath to folder excluded with replacing
					display dialog "This PDF wasn't moved to a final destination. It will be located in the Failed folder. Please move this to it's appropriate location." buttons "OK" default button 1
					open folder excluded
					set bounds of container window of folder excluded to {200, 200, 600, 400}
				end tell
			end if
		on error e
			logError(e)
		end try
	end repeat
	
	return 5 -- return to this handler after 5 seconds
end idle

on logError(theError)
	set logFolder to (path to library from user domain as text) & "Logs:"
	tell (current date) to set timeStamp to short date string & space & time string & ": "
	set logFile to logFolder & logName
	try
		set the logStream to open for access file logFile with write permission
		set logFileEof to get eof of the logStream
		write timeStamp & theError & return to logStream starting at eof as «class utf8»
		close access logStream
	on error
		try
			close access file logFile
		end try
	end try
	
end logError

If you don’t want to use WatchPaths as I suggested and want to keep polling you can also take a look at Bash.

#!/bin/sh while sleep 5 do #Launch code for your AppleScript here done
You’re moving the idle handler again outside AppleScript and will safe you from memory leaks.