I'm facing a big problem. My app is loading XML files (within AsyknTask) from the net and parses them into an local SQLite Database. The problem is after approximately 22 Files and app. 1500 inserts the whole thing crashes with this error:
threadid=8: stack overflow on call to Ljava/lang/String;.hashCode:I
method requires 40+20+0=60 bytes, fp is 0x428cc320 (32 left)
expanding stack end (0x428cc300 to 0x428cc000)
Shrank stack (to 0x428cc300, curFrame is 0x428cc334)
Any idea?
I can parse 20 and then 20 again but not 40 at once.
The content gets cached into an ArrayList and then gets
inserted into the database at the end of each file..
I hope there is a solution or I'm scr** :)
Cheers Ed
The level of recursions was too deep.
The OS crashed approximately within the 23 recursion with an StackOverflow.
Changed it to iteration and everything is fine now!
THANKS!
Related
My current app takes for a cold start ~8 seconds and I want to optimize that.
For that reason I added a log entry in my Application onCreate (Application, not Activity)
override fun onCreate() {
Log.d("myTag", "Calling Application onCreate()")
....
}
When looking in the logs and measuring the time, I found out that the above mentioned 8 seconds consist of the following:
Tapping app icon => Application.onCreate = 4 seconds
Application.onCreate => my Activity visible = 4 seconds
I know I can optimize the time from Application.onCreate() onward. It's my code and I can speed this part up.
But how can I optimize the time the system needs until my Application.onCreate is called?
Thanks!
Sounds like a great usecase for systrace. I usually use (at least) the gfx, input, view, wm, am, res, dalvik, bionic, and sched categories. A -b 10000 to ensure a sufficient buffer size doesn't hurt.
You'll get an html file which can be loaded in a browser, or opened through Chrome/Chromium's built-in chrome://tracing page.
At the top, you'll see CPU details like usage% and which thread is running at which time. Then, you'll see all the processes on the device, containing nested colored blocks ("segments") with information about what's currently going on. At the top of each thread, there is a small colored bar: white is "sleeping" (this includes waiting on a mutex), blue is "waiting for CPU", green is "running on CPU".
If there is a segment that seems interesting but you don't understand the exact meaning of, a search for the text at https://cs.android.com/ can be useful.
In any case, my guess is that you either have some library linking or ContentProviders that take time before Application.onCreate. Both of those would be visible in a systrace. And if my guess is wrong, you'll likely find something else. Good luck! :)
(it could also be class initialization... it'll be interesting to hear what you find!)
My scientific app is fully dynamic and there is only one activity, no fragment or intent.
In some situations, I need to finish the app completely.
So I run
(this as Activity).finishAndRemoveTask()
It works smoothly since Lollipop (Android 5.0), version 21.
Apparently, no app traces or services remains in the memory.
However, I've found a huge problem.
I have some global array or array list (I didn't see other variables).
that remains intact with a new rerun, even a I have a declaration
that empties that variables. It doesn't happen with a rerun via debugger,
should be a new rerun from cell phone.
Below I show a schematic example. I declare in one .kt file, outside any class or function.
class DispFu(
var id: Int = 0,
var isKeyl:Boolean=false,
}
var vDispFu = arrayListOf<DispFu>()
After, I populate vDispFu inside onCreate processing and reach 134 items.
To prove it, I've recorded a file on my phone inside my activity onCreate processing, before exit the program.
fun now():String{
var hora = LocalTime.now()
return "${hora.hour}:${hora.minute}:${hora.second}"
}
var fileDep:File = createOrGetFile(Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_DOWNLOADS),"DepCalc","") // File for debugging
fileDep.appendText("${now()} -> vDispFu size is ${vDispFu.size}\n")
Below there are 2 runs: the first run (inside debugger) and a independent rerun. Here is the file content:
11:3:2 -> vDispFu size is 0
11:3:18 -> vDispFu size is 134
I know that global variables are not recommended, but I just wanted to understand what is going on. It doesn't make sense to me.
If someone could give me some clue about what is happening and give me some alternative strategy, it would be great!
Obviously, for practical reasons, the solution could not involve completely reformulating the program, which has almost 40 thousand lines...
Finishing an Activity doesn't shut down your entire Application or VM, so all global variables continue to stay in memory. When you rerun your application with the debugger, it actually restarts the VM, which is why you're seeing it get cleared in that case.
System.exit() is not an ideal solution since it restarts your VM process. There will be extra churn to do that. It's really intended for abnormal unrecoverable errors. Not necessarily a problem in your particular case.
The more proper way to handle this would be to put your top-level data in a singleton and clear it manually when you are finishing the Activity.
I've solved my problem:
Sometimes, it is incredible how the effort to externalize a problem sometimes helps to solve it ....
The below procedure to quit completely an app:
(this as Activity).finishAndRemoveTask()
It's not enough, despite all the posts about it on Stack Overflow that advocate this strategy.
It's necessary includes other command:
(this as Activity).finishAndRemoveTask()
System.exit(0)
Now:
11:26:25 -> vDispFu size is 0
11:27:1 -> vDispFu size is 0
I have a Firebase Performance Monitoring trace called my_trace.
Now, I start this trace when I load an image:
void loadImage() {
final Trace trace = performance.newTrace("my_trace");
trace.start();
// ... (loading that happens asynchronously)
trace.stop();
}
This works fine when I try to load a single image, however, in my application I need to load many images in parallel.
This means that the following error is reported when I load my images:
Trace 'my_trace' has already started, should not start again!
How do I correctly start a trace multiple times in parallel as I want to record the performance of every single loading process?
Note: I cannot use HTTPMetric as the loading trace also contains image conversion and not just downloading.
You can record it manually by storing the start time yourself and then just recording the duration. This should work.
Reference: https://firebase.google.com/docs/reference/js/firebase.performance.Trace#record
As the error message says, there can only be a single trace with a unique name active at any time. So you'll either have to wait for the first my_trace to finish before starting the second (running them sequentially instead of in parallel), or you'll have to generate a unique name for each trace.
Given how the API is structured it should be possible to allow multiple traces of the same name to run in parallel. If you think Firebase should consider allowing that, I recommend you file a feature request.
Traces are allowed to run in parallel already. Traces are not indexed by trace names. As long the trace object is unique, you should be able to run traces in parallel. Same trace object cannot be re-used.
Eg: (Incorrect way of using trace object)
final Trace trace = performance.newTrace("my_trace");
trace.start();
trace.start(); // This would not work. Fails with the error message that the trace is already started.
// ... (loading that happens asynchronously)
trace.stop();
Eg: Right way using the same trace name multiple times in parallel.
final Trace trace1 = performance.newTrace("my_trace");
final Trace trace2 = performance.newTrace("my_trace");
trace1.start();
trace2.start();
// ... (loading that happens asynchronously)
trace1.stop();
trace2.stop();
I am using Debug.startMethodTracing and Debug.stopMethodTracing to optimize a piece of code that takes about 30 sec to execute but when I open the trace file with trace view it only shows me about 6.5 secondes of trace data.
Any clues ?
The function startMethodTracing by default only logs 8MB of trace data. To get a longer trace, set the second parameter to the maximum trace size you want it to record (in bytes).
startMethodTracing("mytrace", 100000000);
The buffer is limited by the device ram. You cannot specify a too big buffer when calling Debug.startMethodTracing.
I am facing the problem of low memory. Low memory:no more background process And here is the scenario.
I am using a list which gets its data from a string array, it has a custom background, Clicking on item, the list gets another string array to display as second or third level. Information for three levels written in database.
After third level, there are two more levels for which data is going to be fetched from web services,
And that causes the low memory error.
How can I get rid of the solution?
Edit : After having some digging I found that the GC is trying to (kill or) restart in case of its already crashed com.android.inputmethod.latin/.latinIMEservice. One notable point is that the application is translated in french and italian, but this screen does not have any text for translation, does this information helps??
Edit 2: After a detailed study of traceview I found that all the text views have custom fonts applied in it. (There is a call of TypeFace.createFromAsset()) that IMO causes the crashes.
And the problem lies in the fact that I have to keep the fonts....
can It be possible to avoid crash and have the fonts?? (Because i think the answer is no: But still waiting for some opinions)
Edit 3 : After removing the custom fonts the performance of application is much better. Hence I can suspect the font is the only culprit here. And that's why I am editing question. The font I use is helvetica.
Can using external fonts cause application to crash or running out of memory? If yes can you describe the cause in more detail??
Thanks
If you are using code similar to:
Typeface font = Typeface.createFromAsset(getContext().getAssets(),
"fonts/Helvetica.ttf");
try making "font" a global variable so it only gets loaded once. Otherwise it can be loaded repeatedly, quickly consuming memory. See this message for a little more detail
Well, question is a bit unclear to have answered:
After each level - do you switch/start to another Activity? If so you shouldn't keep anywhere references to old activity. Otherwise it could trigger OOM problems
I suppose you're fetching data using some kind of Cursor alike object. Cursor's are very memory-consuming objects, so you'd better not only just close Cursor's, but you should also call Cursor.deactivate()