Memory Leak in Simple Code

Discussion in 'Mac Programming' started by Shadowhawk109, Jun 10, 2010.

  1. Shadowhawk109 macrumors newbie

    Jun 10, 2010
    Hi there,

    I wrote a simple AppleScript that gets a random line from a song playing in iTunes, then outputs that line as well as the next four. I linked it up to Adium through use of AdiumScripts, but it memory leaks like nobody's business, and completely unpredictably. Sometimes I can go a whole day with ~4MB usage (good!), sometimes it takes all of five seconds to use two to three GIGABYTES of RAM.

    Should be noted that I just modified someone elses code; which, as it explicitly says, they were fine with.

    Any advice?

    -- **** by quis 
    -- ****
    -- **** this is a script for use with adium
    -- **** version 1.0
    -- **** do whatever you want with this code
    -- **** see 
    -- ****
    -- **** for more
    on substitute()
    	--You can configure the variables below without changing the logic of the script.
    	--If iTunes is either paused or closed, this is displayed:
    	set quiet to "Silence."
    	--If you'd like a suffix to be displayed (for example, an ellipsis), set it below:
    	set suffix to ""
    	--If you want a comma, if present, at the end of the lyric line itself to be removed, keep this true.
    	--Otherwise, set it to false.
    	--As an example of what this does:  if the lyric chosen is "The lookout has parked the car," (from Kate Bush's song "There Goes a Tenner"), the resulting lyric displayed becomes "The lookout has parked the car" and whatever suffix you've specified, if you've done so.  Note that if your suffix itself is a comma, it will be removed if this option is set to true.
    	--Remember that you can override what's displayed for any song (for example, if it's instrumental and thus has no lyrics) by adding "display lyric as ", followed by whatever you want to display, to the end of the song's comment.
    	--For example, if you wanted a certain classical track to display as "Interlude while I run and get something", append "display lyric as Interlude while I run and get something" to that track's comment.
    	set removeendcomma to true
    	--If there are no lyrics for a song, what do you want to be displayed?  Set it below:
    	set returnifnolyric to "No Lyrics"
    	--Changing things below this may change the logic of the script.
    	--check if iTunes is running...
    	tell application "System Events"
    		set iTunes to ((application processes whose (name is equal to "iTunes")) count)
    	end tell
    	if iTunes is greater than 0 then
    		tell application "iTunes"
    			--...and playing
    			if player state is playing then
    				--grab handler for current track
    				set song to current track
    				--are there lyrics in the comment section?
    				if comment of song contains "display lyric as " then
    					--return comment of song
    					set _chars to characters of ((get comment of song) & "") as list
    					set todisplay to ""
    					repeat with i from ((offset of "display lyric as " in (get comment of song)) + 17) to (length of _chars)
    						set todisplay to todisplay & (get item i of _chars)
    					end repeat
    					return todisplay
    				end if
    				--do lyrics exist?
    				if lyrics of song is equal to "" then
    					return returnifnolyric
    				end if
    				--if neither, fetch current lyrics
    				set final to ""
    				set tuid to database ID of song
    				--get tuid of song that was playing last time this script ran
    				set oldtuid to do shell script "/bin/cat ~/Library/Application\\ Support/Adium\\ 2.0/Scripts/ParaLyrical.AdiumScripts/Contents/Resources/cache.dat"
    				--pass track unique identifier to cache file
    				if tuid as integer is not equal to oldtuid as integer then
    					--	repeat until (final is not "")
    					--get lyrics
    					set lyric to lyrics of song
    					--count lines
    					set paracount to count paragraphs of lyric
    					--set paracount to paracount - 5
    					set boolvalid to false
    					repeat until boolvalid is true
    						--choose a random line
    						set randomnumber to random number from 1 to paracount as integer
    						set randomnumber2 to randomnumber + 1 as integer
    						set randomnumber3 to randomnumber + 2 as integer
    						set randomnumber4 to randomnumber + 3 as integer
    						set randomnumber5 to randomnumber + 4 as integer
    						if randomnumber5 is greater than paracount then
    							set boolvalid to false
    							set boolvalid to true
    						end if
    					end repeat
    					--ORIGINAL CODE
    					set randomline to paragraph randomnumber of lyric
    					set randomline2 to paragraph randomnumber2 of lyric
    					set randomline3 to paragraph randomnumber3 of lyric
    					set randomline4 to paragraph randomnumber4 of lyric
    					set randomline5 to paragraph randomnumber5 of lyric
    					--work some array + for loop magic here?
    					set randompara to paragraph randomnumber of lyric & paragraph randomnumber2 of lyric & paragraph randomnumber3 of lyric & paragraph randomnumber4 of lyric & paragraph randomnumber5 of lyric as list
    					repeat with i from 1 to ((length of randompara) + 5)
    						if (length of item i of randompara) is equal to 0 then
    							set item i of randompara to item (i + 1)
    							set item (i + 1) of randompara to item (i + 2)
    							set item (i + 2) of randompara to item (i + 3)
    							set item (i + 3) of randompara to item (i + 4)
    							set item (i + 4) of randompara to item (i + 5)
    							set item (i + 5) of randompara to item (i + 6)
    						end if
    					end repeat
    					--see if you can fix this to have no blank lines!
    					set lyriclength to count characters of (randomline & randomline2 & randomline3 & randomline4 & randomline5)
    					set lyric to randomline & return & randomline2 & return & randomline3 & return & randomline4 & return & randomline5 & suffix
    					--set lyric to randompara
    					set _chars to characters of lyric as list
    					repeat with i from 1 to (length of _chars)
    						if (get item i of _chars) is "'" then
    							set item i of _chars to "\\'"
    						end if
    					end repeat
    					if removeendcomma is true and ((get item (length of _chars) of _chars) is ",") then
    						set item (length of _chars) of _chars to ""
    					end if
    					--	end repeat
    					--store lyric to linecache.dat
    					do shell script "/bin/echo " & tuid & " > ~/Library/Application\\ Support/Adium\\ 2.0/Scripts/ParaLyrical.AdiumScripts/Contents/Resources/cache.dat"
    					do shell script "/bin/echo " & (items of _chars as string) & " > ~/Library/Application\\ Support/Adium\\ 2.0/Scripts/ParaLyrical.AdiumScripts/Contents/Resources/linecache.dat"
    					--send it over to adium
    					final is equal to items of _chars as string
    					return final
    				else if tuid as integer is equal to oldtuid as integer then
    					--get current song lyric from linecache.dat
    					set existingLyric to do shell script "/bin/cat ~/Library/Application\\ Support/Adium\\ 2.0/Scripts/ParaLyrical.AdiumScripts/Contents/Resources/linecache.dat"
    					set _chars to characters of existingLyric as list
    					--if removeendcomma is true and ((get item (length of _chars) of _chars) is ",") then
    					--	set item (length of _chars) of _chars to ""
    					--end if
    					return items of _chars as string
    				end if
    				return quiet
    			end if
    		end tell
    		return quiet
    	end if
    end substitute
  2. sammich macrumors 601


    Sep 26, 2006
    Yikes, that is some long script. I'd need more time to look in it though.
  3. Shadowhawk109 thread starter macrumors newbie

    Jun 10, 2010
    Sammich, that's fine; I kinda just posted to see if anyone else understands wtf's goin' on.

    Note that there's a LOT of commented out code; rather than just deleting stuff, I commented it out in case I had a brainspark that caused me to continue on the previous path.
  4. rev316 macrumors regular

    Nov 7, 2004
    Unfortunately, I can't run your script (external dependancies).

    However, I suggest you comb through any iteration blocks where the interpreter is allocating tons of memory. Common mistakes.
  5. Shadowhawk109 thread starter macrumors newbie

    Jun 10, 2010
    Shouldn't have any external dependencies (other than, say, iTunes), so that's weird...

    I'm a noob at this, so how do you propose I do that...

Share This Page