ArrayList of PImage eating away at RAM
in
Programming Questions
•
1 year ago
Hi there!
I personally think it has something do to with storing each frame as a PImage in an arraylist. Hence I made a modification which loads ("PImage.get()") each frame on the fly. However the decrease, memory wise, is only 34MB which is why there must be another reason...
If I did something extremely stupid, let me know...I actually hope I did because that means its solveable ;)
I have recenlty begun learning processing and even though I know my way around in programming (I did a bit of java and plenty of python before) I am somewhat stuck on an issue.
I have three PNG files, they are ~158KB each but they are very broad. Within them are animations. It's a single-row animation meaning that the first frame is to the utmost left and the last frame (within the animation) is to the utmost right.
When I loaded in these three images using my AnimatedSprite class I got a OutOfMemory exception. I did manage to remedy it but with my code these 3 animations use up 294MB of RAM.
One modification I made (which loads in the frames on-the-run) cuts that down to 260MB RAM. It's not anything else that causes this because if I run the application without those animations the RAM usage drops to about ~60MB which is acceptable.
Here is my AnimatedSprite class (NOTE If I remove tmpImage = null I get the memory exception) [~294MB]:
- public class AnimatedSprite {
- private int X;
- private int Y;
- public int numberOfFrames;
- private int frameHeight;
- private int frameWidth;
- private int frameAnimationRate;
- private int animationCounter;
- public int lastFrameTime;
- private String spritePath;
- private PImage tmpImage;
- public ArrayList<PImage> animationFrames = new ArrayList<PImage>();
- AnimatedSprite(int xpos, int ypos, int frameW, int frameH, int frames, int animationRate, String path) {
- this.X = xpos;
- this.Y = ypos;
- this.frameWidth = frameW;
- this.frameHeight = frameH;
- this.numberOfFrames = frames;
- this.frameAnimationRate = animationRate;
- this.spritePath = path;
- loadFrames();
- this.lastFrameTime = millis();
- }
- private void loadFrames() {
- println("Load frames called");
- tmpImage = loadImage(this.spritePath);
- for (int i = 0; i < this.numberOfFrames; i++) {
- animationFrames.add(i, tmpImage.get((frameWidth * i), 0, frameWidth, frameHeight));
- }
- tmpImage = null;
- }
- void renderMe() {
- if (millis() - this.lastFrameTime >= this.frameAnimationRate) {
- this.animationCounter = ++this.animationCounter % this.animationFrames.size();
- this.lastFrameTime = millis();
- }
- image(this.animationFrames.get(animationCounter), this.X, this.Y);
- }
- void moveMe(int xtrans, int ytrans) {
- this.X += xtrans;
- this.Y = ytrans;
- }
- int getX() { return this.X; }
- int getY() { return this.Y; }
- int getFrameWidth() { return this.frameWidth; }
- int getFrameHeight() { return this.frameHeight; }
- int getNumberOfFrames() { return this.numberOfFrames; }
- int getDisplayTime() { return this.frameAnimationRate; }
- int getLastTime() { return this.lastFrameTime; }
- void setLastTime(int m) { this.lastFrameTime = m; }
- ArrayList<PImage> getAnimationFrames() { return this.animationFrames; }
- }
This is how I call it:
- AnimatedSprite idleseq_0;
- AnimatedSprite idleseq_1;
- AnimatedSprite idleseq_2;
-
- void setup() {
- size(640, 480);
- idleseq_0 = new AnimatedSprite(100, 100, 188, 365, 105, 20, "idle_seq0.png");
- idleseq_1 = new AnimatedSprite(288, 100, 188, 365, 120, 20, "idle_seq1.png");
- idleseq_2 = new AnimatedSprite(420, 100, 188, 365, 120, 20, "idle_seq2.png");
- }
-
- void draw() {
- background(255);
- idleseq_0.renderMe();
- idleseq_1.renderMe();
- idleseq_2.renderMe();
- }
Here is my modified AnimatedSprite class:
- public class AnimatedSprite {
- private int X;
- private int Y;
- public int numberOfFrames;
- private int frameHeight;
- private int frameWidth;
- private int frameAnimationRate;
- private int animationCounter;
- public int lastFrameTime; //the time at which the last animation was drawn (not last as in LAST of all frames but rather last as in "latest")
- private String spritePath;
- private PImage tmpImage;
- public ArrayList<PImage> animationFrames = new ArrayList<PImage>();
- AnimatedSprite(int xpos, int ypos, int frameW, int frameH, int frames, int animationRate, String path) {
- this.X = xpos;
- this.Y = ypos;
- this.frameWidth = frameW;
- this.frameHeight = frameH;
- this.numberOfFrames = frames;
- this.frameAnimationRate = animationRate;
- this.spritePath = path;
- loadFrames();
- this.lastFrameTime = millis();
- }
- private void loadFrames() {
- println("Load frames called");
- tmpImage = loadImage(this.spritePath);
- // for (int i = 0; i < this.numberOfFrames; i++) {
- // animationFrames.add(i, tmpImage.get((frameWidth * i), 0, frameWidth, frameHeight));
- // }
- // tmpImage = null;
- }
- void renderMe() {
- if (millis() - this.lastFrameTime >= this.frameAnimationRate) {
- //this.animationCounter = ++this.animationCounter % this.animationFrames.size();
- this.animationCounter = ++this.animationCounter % this.numberOfFrames;
- this.lastFrameTime = millis();
- }
- //image(this.animationFrames.get(animationCounter), this.X, this.Y);
- image(this.tmpImage.get((frameWidth * animationCounter), 0, frameWidth, frameHeight), this.X, this.Y);
- }
- void moveMe(int xtrans, int ytrans) {
- this.X += xtrans;
- this.Y = ytrans;
- }
- int getX() { return this.X; }
- int getY() { return this.Y; }
- int getFrameWidth() { return this.frameWidth; }
- int getFrameHeight() { return this.frameHeight; }
- int getNumberOfFrames() { return this.numberOfFrames; }
- int getDisplayTime() { return this.frameAnimationRate; }
- int getLastTime() { return this.lastFrameTime; }
- void setLastTime(int m) { this.lastFrameTime = m; }
- ArrayList<PImage> getAnimationFrames() { return this.animationFrames; }
- }
1