2

To keep this question simple, consider a scenario where I am creating an Android Activity that simply reads data from an external source and uses that data within a TextView. I am seeing dramatic performance differences with the following two scenarios:

  1. Reading the external data and populating the Activity's instance variables to use throughout the Activity. Results in execution time of 2220.479170 ms and the DalvikVM frees memory 12 times.
  2. Reading the external data into local variables each time it needs to be used within class methods. Results in 1150.434916 ms and the DalvikVM frees memory 6 times.

As you can see, using instance variables takes more than 1070 milliseconds longer to execute than using local variables and there are double the amount of memory leaks. The reason why I switched from using local to instance variables is because I was using the same data in different methods, therefore using an instance variable makes more sense than using multiple local variables.

My question is why is the performance much more efficient when using local variables rather than instance variables and why does memory need to be freed double the amount of times?

A code snippet:

public class DataActivity extends Activity {

    //Raw value table entries
    //Table 61
    private int nbr_chns_set1;
    private int nbr_blks_set1;
    private int nbr_blk_ints_set1;
    private int max_int_time_set1;
    //Table 62
    private int blk_end_read_flag;
    private int blk_end_pulse_flag;   
    //Table 63
    private int last_block_element;
    private int nbr_valid_int;
    private int nbr_valid_blocks;
    private int interval_order;
    //Table 64
    ArrayList<String> table64Entries;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lp_data);

        initializeVariables();
        classMethods();     
    }

    public void initializeVariables() {

        //Populate class variables from values in Table 61
        TableReader tableReader = new TableReader(this, R.raw.table61);
        ArrayList<String> table61Entries = tableReader.readTable();
        nbr_chns_set1 = table61Entries.get(98);
        nbr_blks_set1 = table61Entries.get(90);
        nbr_blk_ints_set1 = table61Entries.get(94);
        max_int_time_set1 = table61Entries.get(102);
        blk_end_read_flag = table61Entries.get(22);
        blk_end_pulse_flag = table61Entries.get(26);

        //Populate class variables from values in Table 63
        tableReader = new TableReader(this, R.raw.table63);
        ArrayList<String> table63Entries = tableReader.readTable();
        last_block_element = table63Entries.get(38);
        nbr_valid_int = table63Entries.get(5));
        nbr_valid_blocks = table63Entries.get(34);
        interval_order = table63Entries.get(22);

        //Populate class variables from values in Table 64
        tableReader = new TableReader(this, R.raw.table64);
        table64Entries = tableReader.readTable();

    }

    public void classMethods() {
        ...
    }
McLovin
  • 1,455
  • 3
  • 19
  • 37
  • Some great answers in this question thread related to your question, but they do not directly talk about the performance impacts of one vs. the other: http://stackoverflow.com/questions/1794141/java-instance-variables-vs-local-variables – Bill Mote Apr 01 '13 at 15:04
  • do you get out of memory errors – Raghunandan Apr 01 '13 at 15:19
  • No there are no errors. When I said "memory leaks" I was referring to the amount of times LogCat recorded `GC_CONCURRENT` freeing memory. – McLovin Apr 01 '13 at 15:25
  • 1
    How many times have you repeated the experiment? Did you try it on other devices? You shouldn't draw conclusions if you haven't got enough test data. – Egor Apr 01 '13 at 15:28
  • 2
    GC_CONCURRENT the gc does free up memory. But this not a memory leak. – Raghunandan Apr 01 '13 at 15:34
  • Thanks @Raghunandan, I edited my question and changed "memory leaks" to freed memory". – McLovin Apr 01 '13 at 17:04

1 Answers1

2

Local primitive variables are on the stack. It's scope is local. If you have variable in a method and when the method does it's job, the stack pointer is reset.

Instances variables are stored on the heap. Android does garbage collection my mark and sweep. Instance variables are available for garbage collection when the class itself is avaiable for garbage collection.

http://www.youtube.com/watch?v=_CruQY55HOk. The talk is about memory managment.

http://developer.android.com/training/articles/perf-tips.html.

Simon
  • 14,407
  • 8
  • 46
  • 61
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • Close. Local *primitive* variables are on the stack. Objects are always created on the heap. Also, garbage collection does not operate on the stack frame. When the method exits, the stack pointer is simply reset, "throwing away" the stack frame. – Simon Apr 01 '13 at 15:40
  • @Simon i edited my answer. Does pointer reset mean the stack is cleared by popping the items. when the method ends the variable is removed from the stack.(popped out). – Raghunandan Apr 01 '13 at 15:44
  • The items are not popped. When the method is entered, the current stack pointer is saved. The method is then allocated memory on the stack. When the method exits, the previous stack pointer value is restored therefore releasing the entire stack frame in one operation. – Simon Apr 01 '13 at 15:49
  • I've edited your answer. `void method(){ SomeObject object = new SomeObject();}` This is local but is created on the heap. *Only* primitives are created on the stack. See this http://programmers.stackexchange.com/questions/65281/stack-and-heap-memory-in-java. Remember that in Java, everything is passed by value. The reference to the object is on the stack and if you return the object, a copy of the value of the reference is returned. Then the stack is reset. The object itself is always on the heap. – Simon Apr 01 '13 at 15:52
  • @Simon that's bcoz object is a instance variable. Reference stays on stack while memory for SomeObject is on heap. object is not a primitive variable. – Raghunandan Apr 01 '13 at 15:55
  • 1
    And references are primitives. It's an important distinction because many people assume that creating objects locally does not impact the heap and GC. – Simon Apr 01 '13 at 15:56
  • Thanks for the references on memory management. So for Android programming, is it typically better practice to use local primitives rather than instance primitives since in my particular example the performance is much better? – McLovin Apr 02 '13 at 13:05
  • Maybe moving pointers on stack is faster than accessing instance variables on heap. That's the reason i guess. – Raghunandan Apr 02 '13 at 13:08