Before the app finishes the test, run through the entire aging phase, including data transmission and dispatch, type adb shell top-m 5 found my app PID occupied
CPU is the most, in fact, I want to say that writing an app is not difficult, you do not have a comprehensive analysis of the memory usage of the app? Avoid problems such as oom, and other possible
can bring about some of the occasional problems that some estimates a lot of small partners have not considered, nothing, today to everyone to talk about this aspect of things, although not what difficult
knowledge points, but the most important thing is to develop this kind of habit, in order to reduce unnecessary waste of time in the subsequent development, I will take you how to find and solve the question
Problem, step by step analysis
First look at the CPU usage of our app:
We can see com.digissin.twelve this process is always ranked first, this is the process of our testing, below I take the small friends how to find out to ask
Correct the problem in a timely manner.
First, let's analyze why CPU usage is so high. Is there too much time-consuming operation on the main thread or sub-thread, network operation, new instance object?
With this question, let's look at DDMS and analyze:
View Com.digissin.twelve.rsudpprotocol&postbytesthread 134 lines of code:
The dead loop is caused by the read state, but it cannot be removed because the app needs this dead loop to communicate to the server, as long as it is not an accident, the app is
Keep communication with the backstage! When there is data coming in, Ispause will be set to true, and the code flow will go to if, once a datagram is sent out,
Ispause false While it is used to enter the empty loop, do nothing, and the frequency of the loop executes quickly, if we call sleep in this dead loop ()
Although successful, it is clear that it runs counter to the needs of the app, so it must be ruled out, because once you enter the sleep () thread, you don't work, from the main line
It doesn't make any sense to send a datagram sent by agreement! So this is not the way to take it.
So I quickly thought of a way, that is, when ispause false, we do not need sub-threading work, it is very simple, I just need to let him hibernate, once
There are datagrams coming from the protocol, and we're wakeup to let the child threads continue to work, and that's not wait () and notify () are the first to differentiate between thread and
Object of these two things inside of Wait () and notify (), source analysis is too general, I give you examples of analysis
Calling these 22 functions directly in thread is not going to work, we need to create an object to manage the pauses and continuation of the child threads, which means
A child thread is the equivalent of an ordinary employee, and a new object object is the equivalent of a manager who needs to be notified and informed by the manager, even if the member
Workers know what they want to do next, they need the permission of the manager! Employees can not be independent, just can't do their own things,
Otherwise the entire management mode will be messed up, so we have to create an object to do this pause and continue control on the child thread.
So I loads the synchronized field to this inner class line and add an instanced static method to create this object (Postbytesthread) instance
and give the pause and resume functions:
private static Postbytesthread mthreadinstance = null; Public synchronized static Postbytesthread Getthreadinstance () {if (mthreadinstance = = null) { Mthreadinstance = new Postbytesthread (); } return mthreadinstance; } public synchronized Boolean ispause () {return ispause;} Public synchronized void Setpause (Boolean ispause) {this.ispause = Ispause;} Public byte[] Getpost_bytes () {return post_bytes;} public void Setpost_bytes (byte[] post_bytes) {this.post_bytes = post_bytes;} Public synchronized void Onthreadpause () {try {log.e (TAG, tag+ "onthreadpause ()----"); this.wait ();} catch ( Interruptedexception e) {log.i (TAG, e.tostring ());}} Public synchronized void Onthreadresume () {LOG.E (TAG, tag+ "onthreadresume ()----"); this.notify (); @Override public void Run () {if (Udpsocket = = null) {LOG.I (TAG, tag+ "Udpsocket is null"); Return } while (true) { LOG.I (TAG, tag+ "Ispause () state:" +ispause ()); if (Ispause ()) {try {sendpacket.setdata (getpost_bytes ()); Sendpacket.setlength (Getpost_bytes (). length); Sendpacket.setaddress (serveraddress); Sendpacket.setport (DEFAULT_POTR); Udpsocket.send (Sendpacket); Thread.Sleep (1000); Setpause (FALSE); } catch (Interruptedexception e) {log.i (TAG, "Exception:" +e.tostring ()); } catch (IOException e) {log.i (TAG, "Exception:" +e.tostring ()); }}else{Onthreadpause (); }} } }
Call method, callback interface received from the main thread protocol message packet distribution, and began to work, of course, just for the convenience of everyone to watch, in fact, the start () method does not have to be sent here, because this synchronization object only in the child thread extinction will be recycled, So the equivalent of each time to judge the synchronization of the instance of the object situation
public void Setpostbytesdata (byte[] data) { postbytesthread.getthreadinstance (). Start (); Postbytesthread.getthreadinstance (). Onthreadresume (); Postbytesthread.getthreadinstance (). Setpause (true); Postbytesthread.getthreadinstance (). setpost_bytes (data); Boolean ispause = Postbytesthread.getthreadinstance (). Ispause (); LOG.D ("Postbytesthread", "Postbytesthread Ispause () state:" +ispause); }
After processing this code we continue to look at CPU usage:
We can see that the CPU consumption of the com.digissin.twelve has been greatly reduced, so as to achieve our goal, in solving this problem, I also tell you a
Often made mistakes, and in the form of code and comments to everyone to see clearly
To create an unnecessary new instance:
In the case of some progress bar updating or uploading the download data, we usually need to keep the UI new and so on, which involves the interaction of the child thread with handler, which needs
We are constantly sending a message object to the handler, which makes it easy to make this error, as follows:
@Overridepublic void Run () {while (true) {try {settinglocationtime ()} catch (Interruptedexception e) {E.printstacktrace ();}}} private void Settinglocationtime () throws Interruptedexception{if (Handler!=null) {SendMessage (post_data); time = SETTING_TIME>0?SETTING_TIME:DEFAULT_TIME;//LOG.I (TAG, tag+ "Settinglocationtime () Time:" +time); Thread.Sleep (time*1000);}} /** * This function will run in run while (true) * Message\bundle will be constantly creating new instance objects * So this is a very low error! It's deadly, too! * */private void SendMessage (byte[]data) {Byte[]_data=byteparsebeantools.postprotocolbyte ( Byteprotocolsessiontype.location_state_send, data); Message msg = new Message (); Unnecessary Message new instance object Msg.what=mainsessionutil.send_post_byets_data; Bundle bundle = new bundle (); Unnecessary bundle new Instance Object Bundle.putbytearray (Mainsessionutil.bytes_data_key, _data); Msg.setdata (bundle); Handler.sendmessage (msg);}
Solution:
@Overridepublic void Run () {while (true) {try {settinglocationtime ()} catch (Interruptedexception e) {E.printstacktrace ();}}} private void Settinglocationtime () throws Interruptedexception{if (Handler!=null) {SendMessage (post_data); time = SETTING_TIME>0?SETTING_TIME:DEFAULT_TIME;//LOG.I (TAG, tag+ "Settinglocationtime () Time:" +time); Thread.Sleep (time*1000);}} /** * You can put the bundle in the place where class is loaded, instantiate the object * Once the data is loaded, execute the clear () function before the next call, and the bundle object is equivalent to an iron bowl * each loaded with different water. It avoids having to open up new memory space each time to hold the bundle object * The Message object is simpler, because I callback a handler object, we can directly call the handler object's Obtainmessage () function, This function when handler is created, whether you use it or not, it is there * dies with handler, does not need to be instantiated, does not need to be created, can be taken directly out of the use, which avoids each time to open up a new memory space * To load the message object, Obtainmessage () function from Messagepool * **/private void SendMessage (byte[]data) {bundle.clear ();//Pour out the old water in the bowl (empty the previous cache), fill in the new water (populate the new data from the callback function) Byte[]_data=byteparsebeantools.postprotocolbyte (byteprotocolsessiontype.location_state_send, data); Message msg = Handler.obtainmessage (); From Messagepoolmsg.what=mainsessionutil.send_post_byets_data;bundLe.putbytearray (Mainsessionutil.bytes_data_key, _data);//Install new water (fill new data source) Msg.setdata (bundle); Handler.sendmessage ( msg);}
This way the CPU consumption problem can be greatly reduced, so that the problem can be solved!
Android application Thread CPU GC operatiing and OOM Question 0603-Handy notes