面前app当完成测试,没问题,以完成整个老龄化阶段包含数据收发器,关键在 adb shell top -m 5  我发现我的 app pid 占用 

CPU是最多的,事实上我想说写一个app是不难,你又没有全面的分析app的内存占用?避免一些OOM之类的问题,和其它可

能带来的一些偶发性问题。这些预计非常多小伙伴都没考虑,没事,今天就给大伙说说这方面的东西。虽说不是什么高难度的

知识点,但最重要的是养成这种习惯,才干在兴许的开发中降低不必要的时间浪费。以下我就带大家怎么发现而且解决问

题。一步一步分析



首先看看 我们的app cpu 占用情况:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanNwcGluZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

我们能够看到 com.digissin.twelve 这个进程是一直排在第一位的,这个就是我们測试的进程,以下我带小伙伴们怎么发现问

题,而且及时纠正



首先我们要分析。为什么CPU 占用会那么高?是不是在主线程或者子线程做了耗时操作。网络操作,new 的实例对象过多?

带着这个疑问。我们看看DDMS而且分析下:





查看 com.digissin.twelve.RSUDPProtocol&PostBytesThread 134 行代码:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvanNwcGluZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">



死循环读取状态导致的,但又不能去掉这个死循环,由于app须要这个死循环来给服务端进行通信,仅仅要非意外情况,app是

一直和后台保持通信的!当有数据传过来,isPause 会被设成true,代码流程就会走到if里面,一旦发完一条数据报。

isPause false while 就用进入了空死循环。不干不论什么事情,且频率非常快的循环运行。假设我们在这个死循环里面调用sleep()

尽管能成功。可是非常显然它是与app需求背道而驰的。所以必须排除,由于一旦进入sleep() 线程就不干活了,来自主线成的

协议分发的数据报发送就没不论什么意义了!所以这种方法就不可取了



所以我非常快想到了一个办法,就是当isPause false 的时候,我们就不须要子线程工作。那非常easy,我仅仅须要让他休眠,一旦

有来自协议分发过来的数据报。我们就wakeup 让子线程继续工作。那就非 wait() 和 notify() 莫属了 首先区分 Thread 和 

Object 的 这两个东西里面的 wait() 和 notify() ,源代码分析太笼统了,我给大家举样例分析

在Thread 里直接调用这2两个函数是不会起作用的,我们须要创建一个Object对象来管理子线程的暂停和继续,意思就是说

子线程相当于一个普通员工。被new 出来的Object对象相当于一个管理者,员工要做什么须要管理者来通知和告知,即使员

工知道自己下一步该干什么想干什么,都须要管理者的同意才行!

员工也没法自己独立出来。就是不能自己做自己的事情,

否则整个管理模式会乱套,所以我们必须创建Object对象来对子线程做这个暂停和继续的控制着



所以我给这个内部类线程加 synchronized 字段。而且加入实例化静态方法,来创建这个Object(PostBytesThread)实例对象

别且给出暂停和继续函数:

        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();
}
}
}
}

调用方式,回调接口收到来自主线程的协议消息数据包分发,并開始工作,当然仅仅是为了方便大家观看,事实上start()方法不用发在这里,由于这个同步对象仅仅有在子线程消亡才会被回收,所以相当于每次都多推断了一次这个同步对象的实例情况了

    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);
}

处理完这段代码后我们继续查看 cpu的占用情况:



 

能够看到com.digissin.twelve的CPU占用大幅减少了。从而达到了我们的目的。在解决问题的同一时候,我也给大家说一个

常犯的错误,而且以代码和凝视的形式给大家看清楚

创建不必要的新实例:

在一些进度条更新或者上传下载数据等情况,我们通常须要对UI进行跟新之类的,这就涉及子线程跟Handler的交互。须要

我们不停地向Handler发送Message 对象,这时候就易犯这个错误。例如以下:

	@Override
public 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);
}
}
/**
* 这个函数会在run while(true)里面一直跑
* Message\Bundle会被不停的创建新实例对象
* 所以这是个极低的错误!也是致命的!
* */
private void SendMessage(byte[]data){
byte[]_data=ByteParseBeanTools.PostProtocolByte(
ByteProtocolSessionType.LOCATION_STATE_SEND, data);
Message msg = new Message(); // 不必要的 Message 新实例对象
msg.what=MainSessionUtil.SEND_POST_BYETS_DATA;
Bundle bundle = new Bundle(); // 不必要的 Bundle 新实例对象
bundle.putByteArray(MainSessionUtil.BYTES_DATA_KEY, _data);
msg.setData(bundle);
handler.sendMessage(msg);
}

解决方式:

	@Override
public 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);
}
}
/**
* 能够把Bundle放在class被载入的地方。实例化这个对象
* 装载完一次数据之后,下次调用之前运行clear()函数就可以。此时的bundle对象就相当于一个铁碗
* 每次装不同的水而已,就避免了每次开辟新的内存空间来存放Bundle对象
* Message 对象就更简单了,由于我这类回调了一个Handler对象过来,我们能够直接
* 调用Handler对象的obtainMessage()函数,这个函数当Handler被创建时。无论你用不用。它都在那里
* 随Handler消亡而消亡,不须要实例化。不须要创建,能够直接取出来用。这又避免了每次开辟新的内存空间
* 来装载Message对象,obtainMessage() 函数 来自 MessagePool
* **/
private void SendMessage(byte[]data){
bundle.clear();// 倒掉碗里的老水(清空之前的缓存),装新来的水(填充来自回调函数的新数据)
byte[]_data=ByteParseBeanTools.PostProtocolByte(
ByteProtocolSessionType.LOCATION_STATE_SEND, data);
Message msg = handler.obtainMessage(); // 来自 MessagePool
msg.what=MainSessionUtil.SEND_POST_BYETS_DATA;
bundle.putByteArray(MainSessionUtil.BYTES_DATA_KEY, _data);// 装新的水(填充新的数据源)
msg.setData(bundle);
handler.sendMessage(msg);
}

这样CPU占用问题就能大幅减少,从而问题也能得到解决。



版权声明:本文博主原创文章,博客,未经同意不得转载。

Android Application Thread CPU GC Operatiing and OOM Question 0603-随手笔记的更多相关文章

  1. Android Application Fundamentals——Android应用程序基础知识

    Application Fundamentals--应用程序基础知识 Key classes--关键类 Activity Service BroadcastReceiver ContentProvid ...

  2. Android中关于cpu/cpuset/schedtune的应用

    Android中关于cpu/cpuset/schedtune的应用都是基于进程优先级的,根据不同优先级划分进程类型.AMS(ActivityManagerService)和PMS(PackageMan ...

  3. android Application类的详细介绍(转)

    在代码中经常看到application这个类,一直不知道这个是干什么用的,今天刚好有点时间,所以进行了详细的学习. 一.先对它的整体概念解释: 在android源码中对他的描述是; * Base cl ...

  4. Android application testing with the Android test framework

    目录(?)[-] Android automated testing 1 How to test Android applications Tip 2 Unit tests vs functional ...

  5. (转载)Android 方法数超过64k、编译OOM、编译过慢解决方案。

    Android 方法数超过64k.编译OOM.编译过慢解决方案.   目前将项目中的leancloud的即时通讯改为环信的即时通讯.当引入easeui的时候 出现方法数超过上限的问题. 搜索一下问题, ...

  6. My First Android Application Project 第一个安卓应用

    一.前言: 安卓(Android):是一种基于Linux的自由及开放源代码的操作系统,主要用在移动设备上,如手机.平板电脑.其他的设备也有使用安卓操作系统,比如:电视机,游戏机.数码相机等等. 二.具 ...

  7. Failed to apply plugin [id 'com.android.application'] 和 Could not find com.android.tools.build:gradle:2.XX的最正确的解决方法

    发现android studio是真的可爱啊,上一秒还没问题可以build运行,下一秒就出错...好,你任性,你牛逼.. 说下今天又遇到的两个问题:Failed to apply plugin [id ...

  8. Android中解决图像解码导致的OOM问题

    Android中解决图像解码导致的OOM问题 原文链接:http://blog.csdn.net/zjl5211314/article/details/7042017

  9. eclipse:File->New没有Android Application Project的解决办法

    我的Eclipse版本是:Kepler Service Release 1,截图: 解决步骤: 1.单击Window,选择Customize Perspective,如图: 2.勾选Android A ...

随机推荐

  1. shu_1241 邮局位置问题

    http://202.121.199.212/JudgeOnline/problem.php?cid=1078&pid=5 分析: 由于题目中的距离是折线距离,所以能够分别考虑两个方向.又x方 ...

  2. VSTO学习笔记(一)VSTO概述

    原文:VSTO学习笔记(一)VSTO概述 接触VSTO纯属偶然,前段时间因为忙于一个项目,在客户端Excel中制作一个插件,从远程服务器端(SharePoint Excel Services)上下载E ...

  3. jQuery 自学笔记—5 遍历

    什么是遍历? jQuery 遍历,意为“移动”,用于根据其相对于其他元素的关系来“查找”(或选取)HTML 元素.以某项选择开始,并沿着这个选择移动,直到抵达您期望的元素为止. 下图展示了一个家族树. ...

  4. uva 10003 Cutting Sticks(区间DP)

    题目连接:10003 - Cutting Sticks 题目大意:给出一个长l的木棍, 再给出n个要求切割的点,每次切割的代价是当前木棍的长度, 现在要求输出最小代价. 解题思路:区间DP, 每次查找 ...

  5. 在word 中复选框划勾或叉的方法

    输入大写字母R.大写字母Q ,然后将字体改为Wingdings 2, 就分离得到带框的勾和叉.

  6. Codeforces 61E Enemy is weak 乞讨i<j<k && a[i]>a[j]>a[k] 对数的 树阵

    主题链接:点击打开链接 意大利正在寻求称号 i<j<k && a[i]>a[j]>a[k] 的对数 假设仅仅有2元组那就是求逆序数的做法 三元组的话就用一个树状 ...

  7. SE 2014年4月1日

    一. 描述OSPF报文都有哪些,其作用? OSPF报文主要有:hello报文.DD报文.LSR报文.LSU报文和LSAck报文. Hello报文主要用来建立和维护邻居关系. DD报文是链路状态数据库的 ...

  8. C++:抽象基类和纯虚函数的理解

    转载地址:http://blog.csdn.net/acs713/article/details/7352440 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ...

  9. HashMap源码解读(转)

    http://www.360doc.com/content/10/1214/22/573136_78188909.shtml 最近朋友推荐的一个很好的工作,又是面了2轮没通过,已经是好几次朋友内推没过 ...

  10. Android ImageButton Example 图片按钮

    Android ImageButton Example 图片按钮 使用“android.widget.ImageButton” 展现一个具有背景图片的按钮 本教程将展现一个具有名字为 c.png背景图 ...