Block Array or multidimensional array Variables. For some reason my app is throwing out of memory on my loading of my pub vars class. This started happening when I started using Block Arrays. It works on actual devices but not on the emulators. Any thoughts? Should I set my block arrays to actual needs?
Current Block Arrays:
public static String[][] Name = new String[1000][1000];
however I only use maybe 10 or so. Is the device allocating space for the potential of the 1000 and is that why it is errors out? If so, how can I use these as the need may grow and I do not want to put a small limit on it. Thanks in advance for any thoughts.
With
public static String[][] Name = new String[1000][1000];
you are allocating 1 million strings (1000x1000) which is quite a bunch. If the information on this page is correct each string at least takes 40 bytes, so that would be around 39 Mbytes in your case and this can easily be too much memory on the heap for 1 activity. I would start there to refactor if you are only using 10. There is probably a better solution than your approach but without any more details on your code it's hard to give them. But of the top of my head, why not use a Set<String> or List<String> ?
Edit: So it's seems to me that you just want a Collection that scales dynamically. For that array is not the best choice. There are many of datatypes for that but one simple example whould be an ArrayList which also uses a array as backing datatype but by default will be instanciated with a capacity of 10 and expands dynamically if you continue to add elements
List<String> stringList = new ArrayList<String>();
stringList.add("string1");
stringList.add("string2");
...
If you want each element to have its own list of strings just create an object for that:
public class CompoundString {
private String key;
private List<String> stringList;
...
}
and use it like this
List<CompoundString> compoundStringList = new ArrayList<CompoundString>();
compoundStringList.add(new CompoundString("string1", new ArrayList<String>());
or just use a map:
Map<String,List<String>> stringMap = new HashMap<String,List<String>>();
stringMap.put("string1", new ArrayList<String>());
This is pretty basic concept in most programming languages and I would start to read some docs about the various collections:
http://docs.oracle.com/javase/7/docs/api/java/util/List.html
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
http://www.mkyong.com/java/what-is-the-different-between-set-and-list/
Related
What I am trying to do is keep an original list and two duplicated ones in which to perform operations. Say orginalList is a list of String and has 5 entries
duplicatedList = originalList
secondDuplicatedList = orignalList
duplicatedList.remove(0)
secondDuplicatedList.remove(1)
The values are removed from all three lists and at the end all three lists will have 3 entries.
I have seen a lot of similar questions, but I do not quite get it
Any help or suggestion would be great. thanks
duplicatedList = originalList
Using equal sign will make another pointer to the same location in memory (duplicatedList is not instantiated from scratch); so both duplicatedList & originalList points to the same list
Instead, you need to create a brand new list in memory with the same values of the original list.
You can use the Collection's extension function toMutableList() to do that:
duplicatedList = originalList.toMutableList()
secondDuplicatedList = originalList.toMutableList()
This extension function originally creates a new list:
public fun <T> Collection<T>.toMutableList(): MutableList<T> {
return ArrayList(this)
}
try
duplicatedList.addAll(originalList)
My wanna do the search thing on my app, and I'm using a AutoCompleteTextView that use more than one string-array stored on resources, I'm doing this way:
List<String> list = new ArrayList<>();
String[] array1 = getResources().getStringArray(R.array.array1);
String[] array2 = getResources().getStringArray(R.array.array2);
...
list.addAll(Arrays.asList(array1));
list.addAll(Arrays.asList(array2));
...
AutoCompleteTextView autoView = (AutoCompleteTextView) findViewById(R.id.auto_complete);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list);
autoView.setAdapter(adapter);
It works nicelly, but I'm in doubt when performance and memory of my app, 'cause are many itens on each array (altogether more than 400), so I'm wondering if create a list to add all itens (like I'm doing) can take up too much memory?
This way I'm doing is wrong or it's right? Can harm the app performance?
Anyone knows?
Thx
It doesn't create much problem. It just consume a little memory. I am using approx 8000 items in the list with Auto Complete TextView, Which works fine for me.
If you are worried about this thing, just check your memory usage on device monitor with the both cases.
You can do this like this:
Connect your device via ADB.
Run your App.
Open Logcat/Android Moniter.
Go to monitor tab.
In the monitor tab, you can see CPU, Memory & Network Usages.
Hope this will help.
I'm using a RecycleView with a Gridlayoutmanager. My app loads a lot of items when the user scrolls down.
LinkedList has a good performance when adding new elements, while my ArrayList would need to get constantly resized.
But I'm not sure about what RecycleView does in the background which would work better with an ArrayList and/or a LinkedList.
My adapter would be:
public class PhotosAdapter extends RecyclerView.Adapter<PhotosAdapter.PhotosViewHolder> {
private Context context;
private List<Photo> items;
public PhotosAdapter(Context context, List<Photo> items) {
this.context = context;
this.items = items;
}
//other code here
public void addAll(List<Photo> newItems) {
int beforeSize = items.size()-1;
items.addAll(newItems);
notifyItemRangeInserted(beforeSize, newItems.size());
}
}
So when I create a new empty adapter I can either do this:
new PhotosAdapter(getContext(), new ArrayList<Photo>());
or this:
new PhotosAdapter(getContext(), new LinkedList<Photo>());
And when adding new elements simply:
adapter.addAll(myPhotos);
So would a LinkedList work better in this case? What about RecycleView's optimalized scrolling? Does that work better with an ArrayList or a LinkedList?
Now the first question should be are you optimizing prematurely? Is this a critical part of your app and are you having performance problems?
Anyway ArrayLists will give you better performance in most situations. I'd recommend using it as default and only using linked lists if you want to insert data into the middle of the list.
Yes, ArrayLists need to resize the array when they get too big, but in most cases this won't offset the advantages you get.
Remember that get(int index) is O(n) when using LinkedLists vs O(1) when using ArrayLists. If you're really concerned about adding lots of elements often, you can give the ArrayList a large initial capacity so it won't have to resize too often.
Check out this talk from Bjarne Stroustrup if you're interested. https://www.youtube.com/watch?v=YQs6IC-vgmo
It doesn't matter. Plus, you can always just try both of them and measure the performance.
More likely, the issue lies with something else:
Are you retrieving the data on a background thread?
Are new items being added in between existing items? Or only at the end? If it's only at the end you could try pre-fetching the items when the user is close to the bottom. (Again, by firing off a background thread and listening for a callback)
Are your child views complicated?
Since the code mentions using List, I'm guessing it's a recyclerView with images. The problem could be bitmaps being constantly allocated (and deallocated) memory.
In any case, I recommend profiling. A difference as minuscule as using ArrayList instead of LinkedList doesn't matter in all but the most extreme cases. See what your garbage collector is doing. Look at which method takes the longest to run, try to find what's slowing down your app the most.
I am creating an app that involves reading in data from a file. The file is relatively large (1.8 MB) and is being read from an async thread in onCreate. The very first time the app is started up, it loads just fine. However, if you click the back button and then load it again, it runs out of memory and crashes (throwing the OutOfMemory error).
How do I get it to use the lowest amount of memory possible and/or free that memory when it is done?
File Reading Code (executed in the doInBackground() method of the async class):
public ArrayList<String> createDataList() {
dataList = new ArrayList<String>();
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text.txt")));
String data;
while ((data = br.readLine()) != null) {
dataList.add(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // stop reading
} catch (IOException ex) {
ex.printStackTrace();
}
}
return dataList;
}
EDIT*
Async Class:
private class loadData extends AsyncTask<Void, Void, ArrayList<String>> {
#Override
protected ArrayList<String> doInBackground(Void... arg0) {
dataList = createDataList();
return dataList;
}
protected void onPostExecute(ArrayList<String> result) {
super.onPostExecute(result);
// display first element in ArrayList in TextView as a test
}
}
I have tried splitting up the file based on how I want to organize the data and store the data from each text file into a separate ArrayList but I had memory problems with that as well. I have also stored all of the data into one "master" ArrayList and then invoked a method on that "master" to add the data to the appropriate ArrayList (removing/clearing the data from the "master" as soon as it copied).
Any ideas on how to streamline and reduce memory impact?
EDIT**
Logcat:
That is from when you click the back button and then load the activity again. The following is just one of the messages produced (in verbose):
You can try adding android:largeHeap="true" in your manifest but it is not supported in Android API-8. To my understanding, you are reading and storing the data onto heap memory, which is usually quite limited and its size depends on the device your running your app on.
You might also want to investigate here: android - out of memory
First, make sure you don't have two copies of the data in memory. You can null out the reference to the old ArrayList before starting to create the new one, though you have to do that carefully -- calling ArrayList.clear() first would be more thorough.
Second, figure out how much memory that ArrayList is eating up by using a tool like hprof or Eclipse MAT. If it's using a ton of space, you may want to consider a more compact data representation.
So... from the code snippet, it looks like you're just reading a bunch of text strings in from a file, using a byte-to-char conversion. If the source material is plain UTF-8 (i.e. essentially ASCII), you've got a 2x expansion to UTF-16, plus allocation of the char[] object to hold it, plus the size of the String object that wraps that, plus the overhead of the entry in the ArrayList. Depending on how long an average string in the file is, this can be a significant multiple on your 1.8MB.
One way to avoid this would be to read the file into memory as byte[], scan it to figure out where each string starts, and just keep an array of integers with the start offset of each string. When you need string N, decode it from the byte[] into a String and return it. This reduces your overhead significantly. You could reduce it further by not loading the file and just reading individual strings out as needed (using a RandomAccessFile), but this may slow things down.
Seems to be you might have a bit of trouble with the immutability of Strings .
Why don't you try changing your code so you use StringBuilder for instance? Of course, you'll have to change more than one thing but it would be similar enough to your code and wouldn't fill your memory up as fast.
I am banging my head for the last couple days in order to get this done but Im unable to. Someone please help me out!
Let me not tell u the whole thing and will try to explain it simply n clearly.
Im having 1 ArrayList. I am trying to replicate that into another one and trying to delete an item at a particular index. But this not only deletes the item in the replicated ArrayList but also the original ArrayList.
For ex:
var DuplicateList:ArrayList = new ArrayList();
DuplicateList = OriginalList;
DuplicateList.removeItemAt(2);
The above not only deletes the "Item 3" at Index-2 in the DuplicateList but also in the OriginalList.
I just need some workaround with this approach as this is the only way by which whatever I typed inside the controls present in an ItemRenderer of a FLEX List control that uses the OriginalList as a dataProvider is RETAINED, when I change the dataProvider of the List Control from OriginalList to DuplicateList. The following approach does not retain all the data.
var DuplicateList:ArrayList = new ArrayList();
DuplicateList.addAll(OriginalList);
DuplicateList.removeItemAt(2);
ListCntrl.dataProvider = DuplicateList;
Thanks for your help in advance...
A very, very important thing to understand:
ActionScript3 uses references to objects. Because of that, the two variables in this line of code refer to the exact same instance of an ArrayList:
DuplicateList = OriginalList;
So, when you remove an item from one reference, it is gone from the next. If you want two separate instances of ArrayList, then you need to clone it like you are suggesting later in your code.
So far, so good... but why is your ListCntrl retaining the data from the OriginalList? That doesn't make any sense at all. If you remove an item from DuplicateList and then use it as the data provider, then that item shouldn't be there. I think there is more to this story...