Service和Thread的关系,Handler机制原因,主线程looper.loop()为什么不阻塞主线程,Service不会阻塞,内存溢出和内存泄漏的区别、产生原因以及解决方案

 

Service和Thread的关系

其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同的概念。Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。

额,既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

Handler机制原因,主线程looper.loop()为什么不阻塞主线程

 

Handler,Message,looper 和 MessageQueue 构成了安卓的消息机制,handler创建后可以通过 sendMessage 将消息加入消息队列,然后 looper不断的将消息从 MessageQueue 中取出来,回调到 Hander 的 handleMessage方法,从而实现线程的通信。

从两种情况来说,第一在UI线程创建Handler,此时我们不需要手动开启looper,因为在应用启动时,在ActivityThread的main方法中就创建了一个当前主线程的looper,并开启了消息队列,消息队列是一个无限循环,为什么无限循环不会ANR?因为可以说,应用的整个生命周期就是运行在这个消息循环中的,安卓是由事件驱动的,Looper.loop不断的接收处理事件,每一个点击触摸或者Activity每一个生命周期都是在Looper.loop的控制之下的,looper.loop一旦结束,应用程序的生命周期也就结束了。我们可以想想什么情况下会发生ANR,第一,事件没有得到处理,第二,事件正在处理,但是没有及时完成,而对事件进行处理的就是looper,所以只能说事件的处理如果阻塞会导致ANR,而不能说looper的无限循环会ANR

另一种情况就是在子线程创建Handler,此时由于这个线程中没有默认开启的消息队列,所以我们需要手动调用looper.prepare(),并通过looper.loop开启消

主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。


 

Service不会阻塞:

Service和Thread是两个概念,Thread可以在Service中,可以在activity中,activity中的耗时操作会造成阻塞。阻塞是实际爱你上一直做一件事没完,才造成阻塞的。

Service中的looper.loop,不会阻塞,阻塞是耗时造成界面不能进行刷新,造成的,Service都没有界面,怎么会阻塞,但是会一直loop,只要你的手机有点就会不断吧messageQuenue中的消息取出,进行处理 。Service里面也是可以新建线程进行耗时操作。两个是两种概念,功能上可能会达到某些想的想过但是关系不大。

 

 

1.java中equals和==的区别

基本数据类型==比较的是值,非基本数据类型==比较的是内存地址 

equals比较的是内存地址

 

 

2.平时开发中设计到哪些性能优化,你是从哪些地方来优化,你是通过什么工具来分析的?

笼统的说:就是让App反应更快,使用更稳,流量、电量更省,apk更小。

具体的说:省电优化、内存优化、网络优化、图片优化、UI优化。

更快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。

UI优化:

分析工具:Systrace

(1)减少层级,合理使用 RelativeLayout 和 LinerLayout,合理使用Merge,Include。

(2)提高显示速度,使用 ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。

(3)布局复用,可以通过标签来提高复用。

(4)尽可能少用wrap_content,wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。

(5)删除控件中无用的属性。

更稳:减低 Crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。

(1)增加相应的判断,以及异常处理。

(2)避免在主线程做耗时操作。

更省:节省流量和耗电,节约内存,减少用户使用成本,避免使用时导致手机发烫。

耗电分析工具:Battery Historian

(1)避免浮点运算。

(2)根据客户端图片的大小要求叫UI做相应大小的图提供给服务器,避免过大消耗更多流量和电量。

(3)不用的广播,服务记得及时关闭。

内存分析工具:Memory Monitor

(1)对象引用:强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。

(2)减少不必要的内存开销:注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。

(3)使用最优的数据类型:比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等。

(4)图片内存优化:点9图减少图片大小以及可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等。

更小:安装包小可以降低用户的安装成本。

(1)做混淆优化代码。

(2)删除无用的代码及图片相应的本地库。

(3)Lint优化。

(4)zip压缩。

 

内存溢出和内存泄漏的区别、产生原因以及解决方案:

 

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
 
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到 

 

内存溢出的原因以及解决方法

引起内存溢出的原因有很多种,小编列举一下常见的有以下几种:

1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收
3.代码中存在死循环或循环产生过多重复的对象实体
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小

内存溢出的解决方案:

第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)

第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。

第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

重点排查以下几点:
1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

2.检查代码中是否有死循环或递归调用。

3.检查是否有大循环重复产生新对象实体。

4.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

5.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

第四步,使用内存查看工具动态查看内存使用情况

你可能感兴趣的:(实达)