0

I am currently writing an android app to compare runtime between different data structures and algorithms. When I run my app and started to compute the run time tests for different data structures, the app went out of memory even when the size of n is 100. The only part that ran really slow and got the app out of memory is when calling the static methods to get the runtime. It was pretty fast when I ran it on Eclipse.

Here a part of the logcat (Using the static methods only to get the runtime of ArrayList took about 1 minute when n = 100):

02-03 19:02:02.853      316-685/? D/AudioFlinger﹕ mixer(0xb2140000) throttle end: throttle time(11)
02-03 19:02:02.958    3363-3373/? I/art﹕ Background partial concurrent mark sweep GC freed 12383(516KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 9MB/16MB, paused 5.218ms total 54.521ms
02-03 19:02:03.159    3363-3373/? I/art﹕ Background sticky concurrent mark sweep GC freed 71554(1274KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 19MB/19MB, paused 7.547ms total 98.376ms
02-03 19:02:03.281    3363-3373/? I/art﹕ Background partial concurrent mark sweep GC freed 66258(1895KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 21MB/36MB, paused 9.116ms total 121.088ms
02-03 19:02:03.350    3363-3363/? D/RunTimeComparison﹕ List selected
02-03 19:03:29.714    3363-3363/? D/RunTimeComparison﹕ Added arrayList entries

This method will run when the user click "Test Run" button for the data structures:

 private void runDataStructuresComparison(int n) {
    String dsType = dsTypeSpinner.getSelectedItem().toString();

    List<Integer> arrayList = new ArrayList<Integer>();
    List<Integer> linkedList = new LinkedList<Integer>();
    Set<Integer> hashSet = new HashSet<Integer>();
    Set<Integer> treeSet = new TreeSet<Integer>();
    Map<Integer, Integer> hashMap = new HashMap<Integer, Integer>();
    Map<Integer, Integer> treeMap = new TreeMap<Integer, Integer>();

    Random rand = new Random();

    for (int i = 0; i < n; i++) {
        arrayList.add(i);
        linkedList.add(i);
        hashSet.add(rand.nextInt(n));
        treeSet.add(rand.nextInt(n));
        hashMap.put(rand.nextInt(n), i);
        treeMap.put(rand.nextInt(n), i);
    }

    if (dsType.equalsIgnoreCase("Lists")) {
        Log.d(TAG, "List selected");
        String[] labels = {"Access", "Search", "Random Insertion", "Sequential Insertion",
            "Random Deletion", "Sequential Deletion"};
        List<BarEntry> arrayListEntries = new ArrayList<>();
        arrayListEntries.add(new BarEntry(ListRunTime.accessTime(arrayList, n), 0));
        arrayListEntries.add(new BarEntry(ListRunTime.searchTime(arrayList, n), 1));
        arrayListEntries.add(new BarEntry(ListRunTime.randomInsertionTime(new ArrayList<Integer>(arrayList), n), 2));
        arrayListEntries.add(new BarEntry(ListRunTime.sequentialInsertionTime(new ArrayList<Integer>(arrayList), n), 3));
        arrayListEntries.add(new BarEntry(ListRunTime.randomDeletionTime(new ArrayList<Integer>(arrayList), n), 4));
        arrayListEntries.add(new BarEntry(ListRunTime.sequentialDeletionTime(new ArrayList<Integer>(arrayList), n), 5));

        Log.d(TAG, "Added arrayList entries");

        List<BarEntry> linkedListEntries = new ArrayList<>();
        linkedListEntries.add(new BarEntry(ListRunTime.accessTime(linkedList, n), 0));
        linkedListEntries.add(new BarEntry(ListRunTime.searchTime(linkedList, n), 1));
        linkedListEntries.add(new BarEntry(ListRunTime.randomInsertionTime(new LinkedList<Integer>(linkedList), n), 2));
        linkedListEntries.add(new BarEntry(ListRunTime.sequentialInsertionTime(new LinkedList<Integer>(linkedList), n), 3));
        linkedListEntries.add(new BarEntry(ListRunTime.randomDeletionTime(new LinkedList<Integer>(linkedList), n), 5));
        linkedListEntries.add(new BarEntry(ListRunTime.sequentialDeletionTime(new LinkedList<Integer>(linkedList), n), 5));

        Log.d(TAG, "Added LinkedList Entries");

        BarDataSet arrayListDataSet = new BarDataSet(arrayListEntries, "ArrayList");
        BarDataSet linkedListDataSet = new BarDataSet(linkedListEntries, "LinkedList");

        Log.d(TAG, "BarDataSet created");

        List<IBarDataSet> dataSets = new ArrayList<>();
        dataSets.add(arrayListDataSet);
        dataSets.add(linkedListDataSet);

        BarData data = new BarData(labels, dataSets);
        Log.d(TAG, "Prepare to draw");
        chart.setData(data);
        Log.d(TAG, "Started Drawing Chart");

    } else if (dsType.equalsIgnoreCase("Sets")) {
        String[] labels = {"Search", "Insertion", "Deletion"};

    } else if (dsType.equalsIgnoreCase("Maps")) {
        String[] labels = {"Access", "Search", "Insertion", "Deletion"};

    }
}

Here is an example class to get the list runtimes (I use float for the time since the chart framework I am using uses float):

package RunTimeComplexity;

import java.util.List;
import java.util.Random;


public class ListRunTime {
    private static final Random RAND = new Random();

    public static float accessTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = 0; i < n; i++) {
            list.get(RAND.nextInt(n));
        }
        return Watch.getTime();
    }

    public static float searchTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = 0; i < n; i++) {
            list.contains(RAND.nextInt(n));
        }
        return Watch.getTime();
    }

    public static float randomInsertionTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = 0; i < n; i++) {
            list.add(RAND.nextInt(n), i);
        }
        return Watch.getTime();
    }

    public static float sequentialInsertionTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = 0; i < n; i++) {
            list.add(i);
        }
        return Watch.getTime();
    }

    public static float randomDeletionTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = 0; i < n; i++) {
            list.remove(RAND.nextInt(n - i));
        }
        return Watch.getTime();
    }

    public static float sequentialDeletionTime(List<Integer> list, int n) {
        Watch.start();
        for (int i = n - 1; i >= 0; i--) {
            list.remove(i);
        }
        return Watch.getTime();
    }


}
Hieu
  • 41
  • 4
  • so your question is... ? – rupps Feb 04 '16 at 00:13
  • Sorry, so my question is what can I do to make the static methods that return the runtimes run faster and prevent out of memory. Since it was very fast on Eclipse and ran without any problems. – Hieu Feb 04 '16 at 00:16
  • I'd say it's 2 different problems, speed and memory. First of all I'd check if you're genuinely exhausting your heap. How much memory is expected to take? Does the heap grow uncontrollably? Can you post the logcat depicting how memory is exhausted? You could copy the routine in http://stackoverflow.com/questions/4820353/how-do-i-detect-the-heap-size-usage-of-an-android-application to dump the heap sizes every now and then – rupps Feb 04 '16 at 00:22
  • 1
    Thank you for the help, I figured out and fixed my problem. I initialized too many data structures when the button is clicked, which caused the memory problem. For the speed, I didn't notice I was always getting value from the spinner of 100000, not 100. I ended up just moving some codes and it all worked out. – Hieu Feb 04 '16 at 00:57

0 Answers0