They are places where "Z axis" does not exist, only YX reign, the word is unknown 3D, games are simple but should be played, many of them will make us having a good time

Report article RSS Feed Where has all the Memory Gone?

As I have been working on ASoD 0.75, i have wondered where exactly all my RAM is going. So, I started up a profiler and got some information. The purpose of this article is to educate you on where the RAM in ASoD is going and inform you of plans to optimize the system even further.

Posted by masternerdguy on Aug 26th, 2009

Introduction
As I have been working on ASoD 0.75, i have wondered where exactly all my RAM is going. So, I started up a profiler and got some information. The purpose of this article is to educate you on where the RAM in ASoD is going and inform you of plans to optimize the system even further.

The Chart
The profiling was less than a minute, I just went from one solar system to another, docked, and exited. The RAM fluctuated by about 20% as the garbage collection did its work. Here is the important part of the output.

A profiling of ASoD 0.75b's memory usage.

The immediate conclusion is that the almighty integer has outperformed by far every other type of variable in memory consumption. Indeed, the runner up is a mere 16.1% memory usage to the integer's 67.5% .

Reasons for the Integer to Rank Top
ASoD does not work with doubles or floating points often, and since everything is based on pixels it is all integer form. Integers are used in the many For loops ASoD needs, and are used to define properties such as behaviors. They declare the type of object something is while still finding time to store the sleugh of statistics and numbers needed for player-environment interaction.

java code:
space[68] = new cosmos(0, 5300, 5100, "Station 1");
            space[68].setPlanetTexture(Toolkit.getDefaultToolkit().getImage(getUrl("station_one.png")));
            space[68].solar = "Marcina";
            space[68].dockable = true;
            space[68].setDockedTexture(Toolkit.getDefaultToolkit().getImage(getUrl("slasher_station_docked.png")));
            space[68].selling = new String[]{"Raw Ore", "Weapons", "Argon"};
            space[68].sellingPrices = new int[]{15, 5, 80};
            space[68].buying = new String[]{"Equipment", "Water", "Food", "Ice", "Oxygen", "Narcotics", "Nitrogen", "Carbon Dioxide", "Pirated Software"};
            space[68].buyingPrices = new int[]{20, 30, 20, 9, 30, 150, 18, 20, 1500};
            space[68].availableShips = new String[]{"Slasher Frigate", "Slasher Miner"};
            space[68].shipCost = new int[]{8200, 9500};
            space[68].faction = "Slasher";
            space[68].dockable = true;

In the above code you can see many of the usages of the integer in ASoD. It can be seen defining coordinates, prices, indexes, and object type.

All hail the Rectangle
Without a rectangle there would be no game development at all. Rectangles are perfect shapes for 2D collision testing and other things. The rectangle was the runner up for memory consumption and is the easiest to put on a diet.

Whenever a method runs and creates a local variable, CPU and memory operations are done. At the end of the method the variable is discarded. While for integers this method will be a pain to make all variables global to avoid creation/destruction, the Rectangle is easier. First of all the rectangles created typically need to be shared. In addition some sloppy coding on my part has some global rectangles recreated all-too-often.

java code:
    public Rectangle getBounds() {
        searchForTargetRect = new Rectangle(x - 300, y - 300, 600, 600);
        if (this.targetSpace == 50) {
            this.targetSpace = -100;
            this.targetRat = -100;
        }
        Rectangle r = null;
        try {
            //this.cleanUpNonAgressedHoldStillRats();
            if (type == -50) {
                r = new Rectangle(x, y, 60, 60);
            }
            if (type == -1) {
                r = new Rectangle(x, y, 60, 60);
            }
            if (type == 0) {
                r = new Rectangle(x, y, 50, 50);
            }
            if (type == 1) {
                r = new Rectangle(x + 10, y + 10, 80, 70);
            }
            if (type == 2) {
                r = new Rectangle(x, y, 50, 50);
            }
            if (type == 3) {
                r = new Rectangle(x, y, 200, 200);
            }
            if (type == 4) {
                r = new Rectangle(x, y, 50, 50);
            }
            if (type == 5) {
                r = new Rectangle(x, y, 55, 55);
            }
            if (type == 6) {
                r = new Rectangle(x, y, 120, 120);
            }
            if (type == 7) {
                r = new Rectangle(x, y, 210, 210);
            }
            if (type == 8) {
                r = new Rectangle(x, y, 100, 100);
            }
            if (type == 9) {
                r = new Rectangle(x, y, 140, 140);
            }
            if (type == 10) {
                r = new Rectangle(x, y, 120, 120);
            }
        } catch (Exception e) {
        }
        return r;
    }

The above code is called very often by everything from bullets to NPC navigation. It creates a new bounds every time its called because this is convenient. However, it is likely adding a massive portion of crap variable work that can be avoided. So, by making the rectangle bounds declared at NPC creation and this method only Return the Rectangle, it can save memory operations.

Why Bother?
Seriously, why should I bother? Well, its because in my tests the RAM used by ASoD fluctuated by the second between +20% normal and -20% normal (approximately). This is Java's internal garbage collector picking away these temporary variables and causing lag in the process (often manifesting as a jump or skip in the game every second or so).

ASoD has been optimized and reoptimized, but it still has a lot of potential for slimness. One of the original goals of it was not to waste resources, so I think a round of reoptimization focusing on Variables instead of Procedures is in order.

Post comment Comments
Dragonlord
Dragonlord Aug 26 2009, 5:31pm says:

The best way to optimize is to not rely on the GC at all. Try to avoid creating and destroying objects where possible. Especially take use of in-place variables. For example here in this function make it not "public Rectangle getBounds()" but "public Rectangle getBounds( Rectangle result )" and just fill in the values into the passed in variable. This can be done at all places where a method is called frequently. Avoid allocation and deallocation and especially leaves the GC outside in the cold where it belongs :P

+1 vote     reply to comment
Arxae
Arxae Aug 28 2009, 3:11am says:

what profiler is that in the screenshot? :)

+1 vote     reply to comment
Post a Comment
click to sign in

You are not logged in, your comment will be anonymous unless you join the community today (totally free - or sign in with your social account on the right) which we encourage all contributors to do.

2000 characters limit; HTML formatting and smileys are not supported - text only

Established
Apr 13, 2009
Privacy
Public
Subscription
Open to all members
Contact
Send Message
Email
Members Only
Membership
Join this group
Group Watch
Track this group
News
Browse
News
Report Abuse
Report article
Related Games
Among Seas of Dust
Among Seas of Dust Single Player Futuristic Sim
Related Engines
Custom Built
Custom Built Commercial Released Sep 1, 2007
Related Groups
2D Games
2D Games Fans & Clans group with 134 members
Linux Gamers
Linux Gamers Fans & Clans group with 2,905 members