Author Topic: [SOLVED]Bitmapdata sucking up a lot of memory  (Read 3687 times)

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
[SOLVED]Bitmapdata sucking up a lot of memory
« on: Mon, Sep 24, 2012 »
finally got the profiler working to diagnose my performance issues, For some reason bitmapdata is eating up memory like it's going out of style (just the player and one enemy eats up 16 MB, and the performance monitor hits 32mb used.).

I'm not sure if it's because I'm using larger sprites or something else, cause none of the other classes are anywhere near as performance draining as the bitmapdata.

anyone knows any common issues that would cause bitmapdata to become so memory hungry?



« Last Edit: Thu, Oct 4, 2012 by Dr_shenanigans »

wg/funstorm

  • Global Moderator
  • Key Contributor
  • *****
  • Posts: 596
  • Karma: +0/-0
    • View Profile
    • Funstorm
Re: Bitmapdata sucking up a lot of memory
« Reply #1 on: Mon, Sep 24, 2012 »
Well bitmapdata contains all your image data. Whereas code is just some text. It's normal for a game's size to come almost entirely from the art + audio.

Think about it, if you have a picture you want to display, then the computer needs to know which color each dot in the image is and that information needs to be stored. Iirc, each color channel in a bmpd takes 1 byte (color value between 0-255) per pixel and there's 4 color channels (RGBA). So an 800x600 bmpd for example should take 1 * 4 * 800 * 600 = 1.8MB of memory.

Now every time you load an image, flixel caches a copy of the bitmapdata so that if you want to re-use it can grab it from the cache instead of reloading the whole file. And the flxsprite itself has a bitmapdata that contains the current frame's image data. So that's why often if you have 1 image used by 1 thing in-game the actual memory usage can be double.

You talk about memory, but then you say it's draining performance. Memory usage shouldn't drain performance until the computer gets low on memory. The general consensus seems to be that if your total is under 128MB that's great, under 256MB that's ok, under 512MB and you're approaching danger, 512MB and over you may encounter problems on computers without a lot of ram.

photonstorm

  • Administrator
  • Key Contributor
  • *****
  • Posts: 1502
  • Karma: +1/-0
    • View Profile
    • Photon Storm
Re: Bitmapdata sucking up a lot of memory
« Reply #2 on: Mon, Sep 24, 2012 »
32MB is nothing. I wouldn't even care unless you start getting into the hundreds of MBs used, OR if the memory is just constantly increasing (i.e. you've got a memory leak somewhere)
http://www.photonstorm.com



"Tell me and I will forget, show me and I might remember, involve me and I will understand" - Confucius

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #3 on: Wed, Sep 26, 2012 »
well when there's 32MB being used, the game is playable but very noticeably laggy.

when there's multiple enemies on (past double digits) over 40MB gets used and then the framerate drops so low it's virtually unplayable.

normal flash player is slightly faster than the debug in this regard.

photonstorm

  • Administrator
  • Key Contributor
  • *****
  • Posts: 1502
  • Karma: +1/-0
    • View Profile
    • Photon Storm
Re: Bitmapdata sucking up a lot of memory
« Reply #4 on: Wed, Sep 26, 2012 »
I still reckon something else is causing your speed issues. 32MB is very little indeed. I wouldn't care until it was into the hundreds of MBs personally. I'd start looking elsewhere for the issue (game resolution, objects being created and not destroyed, memory leaks, etc). Start cutting your code back down until there's no problem, then see what causes it to fall over.
http://www.photonstorm.com



"Tell me and I will forget, show me and I might remember, involve me and I will understand" - Confucius

Charlie Riot

  • Highly Super
  • Member
  • **
  • Posts: 69
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #5 on: Wed, Sep 26, 2012 »
What are your Flash Framerate and Game Framerate values? Do they match?

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #6 on: Fri, Sep 28, 2012 »
What are your Flash Framerate and Game Framerate values? Do they match?

EDIT: got TheMiner working, and things... well got weird. I'm gonna post some screencaps of the performance monitors.

EDIT2: I will be posting the other four images in a moment. First one is with enemies alive, second with enemies dead
« Last Edit: Tue, Oct 2, 2012 by Dr_shenanigans »

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #7 on: Tue, Oct 2, 2012 »
here are the other images

first two are with enemies activate, second two are with enemies dead
« Last Edit: Tue, Oct 2, 2012 by Dr_shenanigans »

auriplane

  • Snails!!
  • Contributor
  • ****
  • Posts: 497
  • Karma: +1/-0
  • Snails!!
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #8 on: Tue, Oct 2, 2012 »
Seems like your collision is bogging stuff down.

LaughingLeader

  • Member
  • **
  • Posts: 64
  • Karma: +0/-0
    • View Profile
    • LaughingLeader Blog
Re: Bitmapdata sucking up a lot of memory
« Reply #9 on: Tue, Oct 2, 2012 »
Thought I'd share a similar experience I had. I had collision bogging me down about 18-20 fps (in debug mode) until I switched many of my FlxG.overlaps statements to specific FlxSprite.overlaps stuff in their update code. FlxG.overlaps creates and destroys a new FlxQuadTree each update call I believe, while overlaps doesn't, so creating those FlxQuadTrees can eat up a lot of memory.

So if you have any FlxG.overlaps statements, you could try commenting them out to see if the FPS suddenly goes up/memory usage goes down. If they do, I'd recommend seeing if you could replace some of those statements with more sprite-specific overlaps statements.

auriplane

  • Snails!!
  • Contributor
  • ****
  • Posts: 497
  • Karma: +1/-0
  • Snails!!
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #10 on: Tue, Oct 2, 2012 »
You shouldn't have to worry about memory from the quad trees.  At least, not in my experience.  Just worry about how much time is being spent, and why--how many objects are in the groups being compared?  How many compares are you doing?  Can you do fewer?

Switching away to FlxObject.overlaps might make sense, but don't abandon FlxG.overlaps if it's the right thing to do.  (There isn't nearly enough information for me to tell you what the right thing to do is.)

You could also try the optimization for FlxQuadTree moly posted:

http://forums.flixel.org/index.php/topic,6663.0.html

Although I'd try to address the root cause first.  (I still haven't tried their optimization--I'm skeptical about using * for anything where performance matters, so I'm guessing it could be faster if you traded maintainability for efficiency and canned ObjectPool, but I haven't measured it yet.)

LaughingLeader

  • Member
  • **
  • Posts: 64
  • Karma: +0/-0
    • View Profile
    • LaughingLeader Blog
Re: Bitmapdata sucking up a lot of memory
« Reply #11 on: Tue, Oct 2, 2012 »
You shouldn't have to worry about memory from the quad trees.  At least, not in my experience.  Just worry about how much time is being spent, and why--how many objects are in the groups being compared?  How many compares are you doing?  Can you do fewer?

Switching away to FlxObject.overlaps might make sense, but don't abandon FlxG.overlaps if it's the right thing to do.  (There isn't nearly enough information for me to tell you what the right thing to do is.)
Oh, I haven't completely abandoned FlxG.overlaps. I use it for callbacks still, but my main memory issue with it was when I was checking if the overlap was false (sorry, I should have clarified on this). So I had a statement like this:
Code: [Select]
FlxG.overlap(Registry.playerHitbox, Registry.gameLevel.hitBoxes, hitboxCallback)
if(!FlxG.overlap(Registry.playerHitbox, Registry.gameLevel.hitBoxes))
{
   //whatever reset code here.
}
Which was eating up my framerate, since it was creating those QuadTrees again to check if the overlap was false. Switching to .overlaps helped since I could still do my callback logic, but then be able to reset it if the overlap wasn't happening.

It's worth noting that I do use the optimizations moly posted, but I'm not too sure how much it has improved my game's performance, since removing the if(!FlxG.overlaps(stuffhere)) code cleared up what has hurting my FPS in debug mode (release mode was fine).

auriplane

  • Snails!!
  • Contributor
  • ****
  • Posts: 497
  • Karma: +1/-0
  • Snails!!
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #12 on: Tue, Oct 2, 2012 »
A-ha, I see.  Say, why don't you write it like this?  Does the callback have a state change that prevents it?

Code: [Select]
if (!FlxG.overlap(Registry.playerHitbox, Registry.gameLevel.hitBoxes, hitboxCallback))
{
   //whatever reset code here.
}

By the way, in my current project, I organized the objects into a lot of small groups.  I gained a fair amount of speed by checking if the groups were empty and skipping the collision checks if so:

Code: [Select]
            if (npcs.length)
                FlxG.collide(worldMap.bgmap, npcs);
            if (enemies.length)
                FlxG.collide(worldMap.bgmap, enemies);
            if (bosses.length)
                FlxG.collide(worldMap.bgmap, bosses);
            if (solidItems.length)
                FlxG.collide(worldMap.bgmap, solidItems);

I also have pools for a lot of bullet types, and I do a similar optimization with those, and so on.  It scales pretty well, though I'll probably go back and try to optimize it later.  (It stays at 60fps on my old computer, so I'm pretty happy right now.)

LaughingLeader

  • Member
  • **
  • Posts: 64
  • Karma: +0/-0
    • View Profile
    • LaughingLeader Blog
Re: Bitmapdata sucking up a lot of memory
« Reply #13 on: Wed, Oct 3, 2012 »
A-ha, I see.  Say, why don't you write it like this?  Does the callback have a state change that prevents it?

Code: [Select]
if (!FlxG.overlap(Registry.playerHitbox, Registry.gameLevel.hitBoxes, hitboxCallback))
{
   //whatever reset code here.
}
That then processes the callback if the overlap is false?

My playerHitbox class contains a few hitboxes for the player that detects different things like normal overlap detection, edge detection, and bullet origin detection (it tracks where bullets will spawn from and if they're inside of a wall, then stops the ability to fire if so). They're simple empty sprite boxes of varying sizes.

Ultimately the solution I worked out seems to work better (without hurting my fps), since I change a few things whether or not each hitbox is overlapping something specific. So it was better off in the long run to have to change how I handle hitbox overlapping (my enemies use a similar setup too). I have the overlapping code contained in organized places now, rather than one big callback (or two, since I'm assuming I'd have to use two callbacks for whether or not the FlxG.overlap is true or false).

My hitbox overlap stuff is like this:
Code: [Select]
public function edgeUpdate():void
{
edgeCheck.facing = Registry.Player.facing;
if(Registry.Player.facing == FlxObject.LEFT)
{
edgeCheck.x = Registry.Player.x-7;
}
else
{
edgeCheck.x = Registry.Player.x+7;
}
edgeCheck.y = Registry.Player.y+10;

if(edgeCheck.overlaps(Registry.gameLevel.collisionMap, false, Registry.gameCamera))
{
onEdge = false;
}
else
{
onEdge = true;
}
//trace(Registry.logTime+"[Overlap Check]: On Edge: " + onEdge, Registry.Player.$player.looking);
}
I still use FlxG.overlaps for big groups of things that don't need a check on whether or not they're overlapping. I think having to have a "FlxG.overlaps(stuff1, stuff2, truecallback)" and a "if(!FlxG.overlaps(stuff1, stuff2, fallcallback)" statement for the same stuff would probably start hurting your memory a bit if you have to do that with large amounts of different groups, since you're messing with the Quadtrees twice and destroying them twice.

So, just from what I gathered, it seems like FlxG.overlaps is better for processing statements if the overlap is true, rather than detecting both possibilities, which is where .overlaps can come in, since you can still use overlaps to detect an object's collision against a group.

I'm not sure if my experience with this is relevant to the OP's current problem or not, or if I'm accidentaly hijacking the thread, so apologies if I am.


By the way, in my current project, I organized the objects into a lot of small groups.  I gained a fair amount of speed by checking if the groups were empty and skipping the collision checks if so:

Code: [Select]
            if (npcs.length)
                FlxG.collide(worldMap.bgmap, npcs);
            if (enemies.length)
                FlxG.collide(worldMap.bgmap, enemies);
            if (bosses.length)
                FlxG.collide(worldMap.bgmap, bosses);
            if (solidItems.length)
                FlxG.collide(worldMap.bgmap, solidItems);

I also have pools for a lot of bullet types, and I do a similar optimization with those, and so on.  It scales pretty well, though I'll probably go back and try to optimize it later.  (It stays at 60fps on my old computer, so I'm pretty happy right now.)
I had started to do something similar when I was running through the hitbox trouble by checking if my hitSlopes group length, but I hadn't made the connection that I should do that for my other object groups as well. That's a really great idea. Thanks!

auriplane

  • Snails!!
  • Contributor
  • ****
  • Posts: 497
  • Karma: +1/-0
  • Snails!!
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #14 on: Wed, Oct 3, 2012 »
That then processes the callback if the overlap is false?

No, it processes the callback if the overlap is true.

LaughingLeader

  • Member
  • **
  • Posts: 64
  • Karma: +0/-0
    • View Profile
    • LaughingLeader Blog
Re: Bitmapdata sucking up a lot of memory
« Reply #15 on: Wed, Oct 3, 2012 »
No, it processes the callback if the overlap is true.

Ah, I see. So you can just contain it all within the one statement.

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #16 on: Wed, Oct 3, 2012 »
alright, here's my collision code, could you help me with doing a more efficient way to overlap with large groups?

Code: [Select]
//my collision code
for (var i_0:int = 0; i_0 < enemies.length; i_0++)
{
                        //is the player NOT invincible?
if (_playerLower.flickering == false)
{
//check if an enemy's alive
if(enemies.members[i_0].alive == true)
{
FlxG.collide(_playerLower, enemies, pain) //enemy hurts the player
}
}
// Checks on-screen bullets for overlap
for (var i:int = 0; i < armory.length; i++)
{ // If overlap occurs, records which bullet hit
if (FlxG.overlap(armory.members[i], enemies.members[i_0])) //armory is the flxweapon group that the player uses.
{
bulletNum = i;
enNum = i_0;
}
}
}

FlxG.overlap(armory, enemies, col_armory_enemies) //causes damage to the enemies
FlxG.collide(_playerLower, stage.floorMap);
FlxG.collide(enemies, stage.floorMap);

auriplane

  • Snails!!
  • Contributor
  • ****
  • Posts: 497
  • Karma: +1/-0
  • Snails!!
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #17 on: Wed, Oct 3, 2012 »
This is why it's slow:

Code: [Select]
for (var i_0:int = 0; i_0 < enemies.length; i_0++)
{

                        ...

// Checks on-screen bullets for overlap
for (var i:int = 0; i < armory.length; i++)
{ // If overlap occurs, records which bullet hit
if (FlxG.overlap(armory.members[i], enemies.members[i_0])) //armory is the flxweapon group that the player uses.
{
bulletNum = i;
enNum = i_0;
}
}

This creates armory.length * enemies.length quadtrees each frame, instead of one.  So if you had 20 bullets and 20 enemies, that'd probably be around 400 times slower than it should be.  You'd do better to use a single FlxG.overlap call to check if any of the bullets hit any of the enemies.  You can record things like which bullet # hit using a callback, if that's useful information.

LaughingLeader

  • Member
  • **
  • Posts: 64
  • Karma: +0/-0
    • View Profile
    • LaughingLeader Blog
Re: Bitmapdata sucking up a lot of memory
« Reply #18 on: Wed, Oct 3, 2012 »
This is why it's slow:

Code: [Select]
for (var i_0:int = 0; i_0 < enemies.length; i_0++)
{

                        ...

// Checks on-screen bullets for overlap
for (var i:int = 0; i < armory.length; i++)
{ // If overlap occurs, records which bullet hit
if (FlxG.overlap(armory.members[i], enemies.members[i_0])) //armory is the flxweapon group that the player uses.
{
bulletNum = i;
enNum = i_0;
}
}

This creates armory.length * enemies.length quadtrees each frame, instead of one.  So if you had 20 bullets and 20 enemies, that'd probably be around 400 times slower than it should be.  You'd do better to use a single FlxG.overlap call to check if any of the bullets hit any of the enemies.  You can record things like which bullet # hit using a callback, if that's useful information.

Ouch. Yeah, auriplane is right. FlxG.collide calls FlxG.overlap as well, which creates/destroys a new FlxQuadTree every time it's called. So you have your first part of your for loop creating/destroying a bunch of FlxQuadTrees (depending on how many enemies you have, though even if you just had two enemies on screen, it's still really inefficient to call FlxG.collide on them separately). Next you have that if statement checking for FlxG.overlap for each bullet. Even though it's an if statement, that still creates/destroys new FlxQuadTrees each time it's called in the update loop.

You could get way better performance if you simply put all those enemies into a FlxGroup and call FlxG.collide((_playerLower, enemies, pain) once. You can put some conditionals before it if you want (like:
Code: [Select]

if(enemies.length > 0 && !_playerLower.flickering)
{
    FlxG.collide(_playerLower, enemies, pain);
}

The same applies to your bullets. Just check the whole group of bullets against the whole group of enemies, with a callback if you want to track which bullet gets hit.
Code: [Select]
if(enemies.length > 0 && armory.length > 0)
{
   FlxG.overlap(armory, enemies, bulletOverlap);
}

var bulletOverlap:Function = function(bullet:FlxObject, enemy:FlxObject):void
{
   if(bullet != null && enemy != null)
    {
        enNum = enemy.members.indexOf(enemy); // If this doesn't work there's other ways of tracking which enemy was hit, like giving them an ID when you instance them, and then recording that ID when they get hit, and so on.
    }

}

That way you'll only be creating two FlxQuadTrees each call of update, rather than potentially one for each enemy and each bullet.
« Last Edit: Wed, Oct 3, 2012 by LaughingLeader »

Dr_shenanigans

  • Member
  • **
  • Posts: 92
  • Karma: +0/-0
    • View Profile
Re: Bitmapdata sucking up a lot of memory
« Reply #19 on: Thu, Oct 4, 2012 »
Code: [Select]
if(enemies.length > 0 && !_playerLower.flickering)
{
    FlxG.collide(_playerLower, enemies, pain);
}

it worked!

thank you so much!

;D

it's always little things that screw me up, ALWAYS.