views:

58

answers:

4

Our server recently has been going down a lot and I was tasked to improve the memory usage of a set of classes that was identified to be the culprit.

I have code which initializes an instance of an object and goes like this:

boolean var1; boolean var2; . . . boolean var100;

void setup() {
 var1 = map.hasFlag("var1");
 var2 = map.hasFlag("var2);
 .
 .
 .
 if (map.hasFlag("some flag") {
     doSomething();
 }
 if (var1) {
   increment something
 }
 if (var2) {
   increment something
 }

}

The setup code takes about 1300 lines. My question is if it is possible for this method to be more efficient in terms of using too many instance variables.

The instance variables by the way are used in a "main" method handleRow() where for example:

handleRow(){
   if (var1) {
     doSomething();
   }
   .
   .
   . 
   if (var100) {
     doSomething();
    }
}

One solution I am thinking is to change the implementation by removing the instance variables in the setup method and just calling it directly from the map when I need it:

handleRow(){
  if (map.hasFlag("var1") {
      doSomething();
  }
  .
  .
  . 
  if (map.hasFlag("var100") {
     doSomething();
  }
}

That's one solution I am considering but I would like to hear the inputs of the community. :)

+7  A: 

If these are really all boolean variables, consider using a BitSet instead. You may find that reduces the memory footprint by a factor of 8 or possibly even 32 depending on padding.

Jon Skeet
I didn't know about BitSet +1
Jeune
EnumSet would also fit.
josefx
+1  A: 

You could save memory at the cost of time (but if your memory use is a real problem, then it's probably a nett gain in time) by storing the values in a bitset.

If the class is immutable (once you create it, you never change it) then you can perhaps gain by using a variant on Flyweight pattern. Here you have a store of in-use objects in a weak hashmap, and create your objects in a factory. If you create an object that is identical to an existing object, then your factory returns this previous object instead. The saving in memory can be negliable or massive depending on how many repeated objects there are.

If the class is not immutable, but there is such repetition, you can still use the Flyweight pattern, but you will have to do a sort of copy-on-write where altering an object makes it change from using a shared internal representation to one of its own (or a new one from the flyweight store). This is yet more complicated and yet more expensive in terms of time, but again if its appropriate, the savings can be great.

Jon Hanna
+1  A: 

You can use command pattern:

public enum Command {

    SAMPLE_FLAG1("FLAG1") {
        public abstract void call( ){
          //Do you increment here
        }
    },
    SAMPLE_FLAG2("FLAG2") {
        public abstract void call( ){
          //Do you increment here
        }
    };

    private Map<String, Command> commands = new HashMap<String, Command>( );

    static {
       for ( Command cmd : Command.values( )) {
           commands.put( cmd.name, cmd);
       }
    };



    private String name;
    private Command( String name) {
        this.name = name;
    }

    public Command fromString( String cmd) {
        return commands.get( cmd);
    }
    public abstract void call( ); 
}

and then:

for( String $ : flagMap.keySet( )) {
   Command.fromString( $).call( ); 
}
Artem Barger
This sounds exciting :)
Jeune
+1  A: 

100 boolean variables will take 1.6k of memory when every boolean with overhead takes 16 bytes (which is a bit much imho) I do not think this will be the source of the problem.

Replacing these flags with calls into the map will negatively impact performance, so your change will probably make things worse.

Before you go redesigning your code (a command pattern looks like a good candidate) you should look further into where the memory leak is that you are asked to solve.

Look for maps that the classes keep adding to, collections that are static variables etc. Once you find out where the reason for the memory growth lies you can decide which part of your classes to refactor.

rsp
This makes sense. I think I am going to look more into the root cause of the problem. :)
Jeune