My apologies for posting the whole class, but since I'm not exactly sure what the problem is, I didn't want to leave any of it out...
Basically, I have a class that handles the background image of a Flash site. The home page has a rotation of images, and then depending on what section the user navigates to, that rotation may stop and a different section image will load in.
I'm getting reports of a memory leak on the home rotation, where if you just let the site sit there for awhile eventually the browser will crash because the rotation keeps using more and more memory.
I'm removing the previous image after the newest one loads in, by removeMovieclip, so it shouldn't ever be the case that there are layers upon layers of images piling up.
Additionally, there is a series of textual promos that cycle over the home images as well. Their cycle is also maintained by a removeMovieClip on the preview promo once the newest has fully loaded.
Can anybody help me understand why this is resulting in crazy memory bloat? Is it because the images files are being re-loaded each time during the loop, rather than being loaded once and just used over and over? I assumed that removing the previous image after its use would result in the memory it occupied in Flash being released, but maybe that's not the case...
Any help from someone more knowledgeable about memory management than I would be greatly appreciated.
Thanks 
import mx.utils.Delegate; import mx.transitions.Tween; import mx.transitions.easing.*;
class com.project.content.LifestylePhoto extends MovieClip {
private var photoCount:Number = 0;
private var photoWidth:Number = 1600;
private var mcBG:MovieClip;
private var mcPromos:MovieClip;
private var bgColor:Color;
private var promoColor:Color;
private var mcDropShadow:MovieClip;
private var mcPhotoShell:MovieClip;
private var mcPhotoMask:MovieClip;
private var photoListener:Object = new Object();
private var photoLoader:MovieClipLoader;
private var loading:Boolean = false;
private var homePhotos:Array;
private var homePhotosTotal:Number = null;
private var homePhotosCount:Number = 0;
private var homePhotoIntervalId:Number;
private var promoSwitchIntervalId:Number;
private var promoCount:Number;
private var promoCycleDelay:Number = 8; // time in seconds
private var loadingHome:Boolean = false;
public function LifestylePhoto(){
mcBG._alpha = 100;
bgColor = new Color(mcBG);
bgColor.setRGB(_root.skinArray["background"]["photoBGColor"]);
};
private function onLoad():Void{
// create photo listener
photoLoader = new MovieClipLoader();
photoLoader.addListener(photoListener);
photoListener.onLoadStart = Delegate.create ( this, onPhotoLoadStart );
photoListener.onLoadInit = Delegate.create ( this, onPhotoLoadInit );
mcPhotoShell.setMask(mcPhotoMask);
// load the "home" photo(s) by default
homePhotos = _root.baseXML.firstChild.attributes.bg.split(",");
homePhotosTotal = homePhotos.length-1;
loadPhoto("home");
};
private function onPhotoLoadStart(mc:MovieClip):Void{
loading = true;
mc.alpha = 0;
};
private function onPhotoLoadInit(mc:MovieClip):Void{
loading = false;
photoCount++;
mc._alpha = 0;
mcPhotoMask._alpha = 100;
var photoFadeIn = new Tween(mc, "_alpha", Strong.easeOut, mc._alpha, 100, 2, true);
photoFadeIn.onMotionFinished = Delegate.create ( this, onTweenMotionFinished );
};
private function onTweenMotionFinished():Void{
if (photoCount > 1){
for (var i:Number = photoCount-1; i>photoCount-10; i--){
this["pshell"+(i-1)].removeMovieClip();
}
}
};
public function loadPhoto(section:String):Void{
if (loading){
// another photo is already loading - cancel it before proceeding to avoid bugs
photoLoader.removeListener(photoListener);
photoLoader.addListener(photoListener);
}
if (section == "home"){
// cycle through home images
if (!loadingHome){
// create the interval for cycling throug home images
homePhotoIntervalId = setInterval(this, "cycleHomePhoto", 8000);
if (_root.navArray["promos"]["bottom"].childNodes.length > 0){
createPromos();
}
}
loadingHome = true;
var photo = mcPhotoShell.createEmptyMovieClip("pshell"+photoCount, mcPhotoShell.getNextHighestDepth());
photoLoader.loadClip(_root.baseDir+"/images/skins/"+_root.issue+"/photos/home/"+homePhotos[homePhotosCount]+".jpg", photo);
} else {
if (_root.photoBackgrounds[section] == 1){
loadingHome = false;
clearInterval(homePhotoIntervalId);
var photo = mcPhotoShell.createEmptyMovieClip("pshell"+photoCount, mcPhotoShell.getNextHighestDepth());
photoLoader.loadClip(_root.baseDir+"/images/skins/"+_root.issue+"/photos/"+section+".jpg", photo);
}
}
};
private function cycleHomePhoto():Void{
if (loadingHome){
if (homePhotosCount < homePhotosTotal){
homePhotosCount++
} else {
homePhotosCount = 0;
}
loadPhoto("home");
}
};
public function stageResize():Void{
var leftEdge:Number = Math.ceil((Stage.width/2)-(photoWidth/2));
mcBG._width = Stage.width;
mcDropShadow._width = Stage.width;
mcPhotoShell._x = leftEdge;
mcPhotoMask._x = leftEdge;
if ((leftEdge) <= 0){
mcPromos._x = 15;
} else {
mcPromos._x = leftEdge+15;
}
};
// --------------------
// PROMOS
// --------------------
private function createPromos():Void{
mcPromos = this.createEmptyMovieClip("promos_mc", this.getNextHighestDepth());
mcPromos._y = 250;
promoColor = new Color(mcPromos);
promoColor.setRGB(_root.skinArray["nav"]["photoPromoText"]);
stageResize();
buildPromo(0);
if (_root.navArray["promos"]["home"].childNodes.length > 1){
startPromoInterval();
}
};
private function startPromoInterval():Void{
clearInterval(promoSwitchIntervalId);
promoSwitchIntervalId = setInterval(this, "cyclePromo", promoCycleDelay*1000);
};
private function clearPromoInterval():Void{
clearInterval(promoSwitchIntervalId);
};
private function buildPromo(pid:Number):Void{
promoCount = pid;
var promoHtmlString:String = "<p align=\"right\"><font size=\"20\" color=\"#"+_root.skinArray["nav"]["photoPromoText"].substr(2)+"\">";
if (_root.navArray["promos"]["home"].childNodes[pid].childNodes.length > 1){
promoHtmlString += _root.navArray["promos"]["home"].childNodes[pid].childNodes[0].firstChild.nodeValue+"<br>"+_root.navArray["promos"]["home"].childNodes[pid].childNodes[1].firstChild.nodeValue;
} else {
promoHtmlString = _root.navArray["promos"]["home"].childNodes[pid].childNodes[0].firstChild.nodeValue;
}
promoHtmlString += "</font></p>";
mcPromos.promolink_mc.removeMovieClip();
mcPromos.attachMovie("labeltext", "promolink_mc", mcPromos.getNextHighestDepth());
mcPromos.promolink_mc._alpha = 0;
mcPromos.promolink_mc.initLabelText(promoHtmlString, true, true, true, 425, 'homepromo');
mcPromos.promolink_mc.promoURL = _root.navArray["promos"]["home"].childNodes[pid].attributes.l;
mcPromos.promolink_mc.useHandCursor = true;
mcPromos.promolink_mc.onRollOver = Delegate.create (this, promoOnRollOver);
mcPromos.promolink_mc.onRollOut = mcPromos.promolink_mc.onDragOut = Delegate.create (this, promoOnRollOut);
mcPromos.promolink_mc.onRelease = Delegate.create (this, promoOnRelease);
var fadePromoIn = new Tween(mcPromos.promolink_mc, "_alpha", Strong.easeInOut, mcPromos.promolink_mc._alpha, 100, 1, true);
};
private function cyclePromo():Void{
var fadePromoOut = new Tween(mcPromos.promolink_mc, "_alpha", Strong.easeInOut, mcPromos.promolink_mc._alpha, 0, 1, true);
fadePromoOut.onMotionFinished = Delegate.create (this, clearPromo);
};
private function clearPromo():Void{
mcPromos.promolink_mc.removeMovieClip();
if (promoCount < _root.navArray["promos"]["home"].childNodes.length-1){
buildPromo(promoCount+1);
} else {
buildPromo(0);
};
};
private function promoOnRollOver():Void{
promoColor.setRGB(_root.skinArray["nav"]["photoPromoTextHighlight"]);
};
private function promoOnRollOut():Void{
promoColor.setRGB(_root.skinArray["nav"]["photoPromoText"]);
};
private function promoOnRelease():Void{
_root.scpNavigation.loadContent(mcPromos.promolink_mc.promoURL, null, null);
};
public function showHomePromo():Void{
mcPromos._visible = true;
mcPromos._alpha = 0;
var promoTween = new Tween(mcPromos, "_alpha", Strong.easeOut, mcPromos._alpha, 100, 1.5, true);
startPromoInterval();
cyclePromo();
};
public function hideHomePromo():Void{
clearInterval(promoSwitchIntervalId);
var promoTween = new Tween(mcPromos, "_alpha", Strong.easeOut, mcPromos._alpha, 0, .5, true);
promoTween.onMotionFinished = Delegate.create (this, disableHomePromo);
};
private function disableHomePromo():Void{
mcPromos.promolink_mc.removeMovieClip();
mcPromos._alpha = 0;
mcPromos._visible = false;
};
};
I think I may have solved it like so:
if (mcPhotoShell["pshell_home"+homePhotos[homePhotosCount]] == undefined){ var photo = mcPhotoShell.createEmptyMovieClip("pshell_home"+homePhotos[homePhotosCount], mcPhotoShell.getNextHighestDepth()); photoLoader.loadClip(_root.baseDir+"/images/skins/"+_root.issue+"/photos/home/"+homePhotos[homePhotosCount]+".jpg", photo); } else { onPhotoLoadInit(mcPhotoShell["pshell_home"+homePhotos[homePhotosCount]]); }
Basically, checking to see if the container for that particular image already exists, and if so simply passing it to the onPhotoLoadInit function (which fades it in) rather than deleting the previous clips and reloading.