异常处理

1.空指针(NullPointerException)                    java层代码问题
调用 null 对象的实例方法。
访问或修改 null 对象的字段。
如果一个数组为null,试图用属性length获得其长度时。
如果一个数组为null,试图访问或修改其中某个元素时。
在需要抛出一个异常对象,而该对象为 null 时。

2.CalledFromWrongThreadException
在主线程之外的线程中进行了修改主界面UI的操作
解决:  1、Activity.runOnUiThread(Runnable)
2.Handler
  sendMessage(Message)
  post(Runnable)
3.AsyncTask
  execute()
    doInBackground()

  onPostExecute()

3.Resources$NotFoundException: String resource ID
TextView.setText(int)时报此错误

4.ClassNotFoundException   在编译的时候在classpath中找不到对应的类而发生的错误。
1 所需要的支持类库放错了地方,并没有放在类路径(CLASSPATH环境变量)里面。
2 使用了重复的类库,且版本不一致。导致低版本的被优先使用。
3 类名错了,一般是使用Class.forName的时候,手工指定了类名的情况。
4 没有导入纯JAVA驱动包。

5.NoClassDefFoundError发生在编译时对应的类可用,而运行时在Java的classpath路径中,对应的类不可用导致的错误。

6.java.lang.ArithmeticException    异常的运算条件(除以零)

7.java.lang.ArrayIndexOutOfBoundsException 数组下标越界

8.java.lang.IllegalAccessException      "没有访问权限",当应用程序要调用一个类,但当前的方法即没有对该类的访问权限便会出现这个异常。

9.ClassCastException        类转换异常

10.NegativeArray Exception     数组负下标异常

11.FileNotFoundException      当java程序试图打开指定路径名表示的文件失败时,抛出此异常。

12.NumberFormatException      字符串转换为数字异常

https://blog.csdn.net/qq_33450379/article/details/53731318

*************************************************************************************************************

OOM
程序申请内存过大,虚拟机无法满足我们,然后自杀了。Android系统的APP每个进程或者虚拟机有最大内存限制,一旦超过这个限制系统就会抛出OOM错误。跟手机剩余内存是否充足没有多少关系。
(1)要开发者使用内存更加合理。
(2)屏幕显示内容有限,内存足够即可。
Android的GC会按照特定的算法来回收不使用的资源,但是gc一般回收的是无主的对象内存或者软引用资源。

1.堆溢出

当报错信息java.lang.OutOfMemoryError后面带有java heap space时,说明是java堆溢出。
  • 1

由于Heap是用来存放实例的,堆溢出,也就说明了当前的实例对象过多,而且这些对象一直处于存活状态(JVM判断对象是否存活,是通过判断GC Roots和对象之间的是否存在可达路径)。出现这种问题,一般要考虑下列两种情况:

  • 内存泄露:

一般出现这种情形,需要判断是否是内存泄露,即一些无用对象一直被引用,导致GC无法有效回收它,这时可以通过一些工具,Optimizeit Profiler,JProbe Profiler,JinSight , Rational 公司的Purify等。查看Heap dump,看看GC roots到对象之间的引用链,定位到泄露的对象。这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,

https://blog.csdn.net/anxpp/article/details/51325838

  • 内存溢出:

另一种情形就是内存溢出,也就是这些对象的确是需要存活的,因此也就不存在GC回收异常。一般这种情况,可能是对象过大,或者对象的生命周期过长,需要从业务层面,减少这些对象在运行期的内存消耗。 
另外一种情形,也有可能是我们的堆分配的内存过小,可以通过配置堆的参数(-Xmx最大内存与-Xms 最小内存)来设置

2.栈溢出

栈溢出需要建立两个概念,一个就是整个java stack区域的大小,一个就是单个线程中stack的大小。

整个stack区的大小是由jvm的内存容量- heap容量 - 方法区容量 确定的,是一个固定的值。 
单个线程中 stack的大小也是固定的,可以通过 -Xss 配置

StackOverflowError,线程请求的栈的深度超过虚拟机允许的最大深度。

每个线程中stack的容量是固定,由于stack是用于存放各个方法的内部变量表的,所以,当大量的方法被调用,而又未及时结束,或者单个方法内部定义了大量局部变量,使单个栈帧很大,这样使得占用的空间超过了单个线程中stack的深度,因此会报这个异常。

OutOfMemoryError 虚拟机扩展栈时无法分配足够的内存空间

一般情况下,当启用一个线程时,就会给这个线程分配一个固定大小的stack,由于整个java stack区的大小是有限的,当我们的线程过多时,就会抛出OutOfMemoryError异常。由此可见,单个线程stack的大小并非越大越好,因为这与我们的线程数息息相关。

3.方法区溢出 
方法区是用于存放类的定义Class文件和常量池等,由此可见,当类或者常量池过多时,会造成方法区溢出

当报错信息java.lang.OutOfMemoryError后面带有PremGen space时,说明是方法区溢出。
  • 1

当前的一些框架,如Spring、Hibernate等,会使用CGlib技术对类进行增强,相应地会增加类的大小; 
还有一些应用,会动态生成JSP文件,JSP文件是需要编译成Class文件的,大量的文件也有溢出的可能; 
或者开发代码中往常量池添加过多的常量,也有可能造成常量池溢出。 
另外一种可能就是我们的应用本身的类就太多,而方法区设置的容量不足,也会容易溢出。 
设置方法区的大小,可通过配置-XX:PremSize 设置最小值,-XX:MaxPremSize设置最大值。

一般而言,android中常见的原因主要有以下几个:
1.数据库的cursor没有关闭。
2.构造adapter没有使用缓存contentview。
3.调用registerReceiver()后未调用unregisterReceiver().
4.未关闭InputStream/OutputStream。
5.Bitmap使用后未调用recycle()。
6.Context泄漏。
7.static关键字等。
 
接下来分别对这些溢出情况说出解决的思路:
1.针对数据库cursor没有关闭的情况,如果我们查询数据库得到的数据量比较小的话是不会造成内存溢出的,但是如果太大的话就容易发生这种异常,所以当我们在使用完Cursor的时候就应该手动调用它的close方法关闭cursor.
 
2.针对adapter没有复用convertView的情况,在我们开发的过程中,经常会遇到一个listview加载成百上千条的数据,如果不复用convertView的话就会在每次执行getView方法的时候都创建一个新的对象,而这个方法的调用速度又是很快的,java不能够及时的回收内存就会造成OOM异常,这时候除了要在getView方法里面对convertView进行判断后复用,还应该使用ViewHolder类来保存通过过findViewById得到的子控件地址值.
 
3.在activity中注册了广播,但是在activity退出的时候没有取消注册的话可能会造成内存溢出,需要手动的在相应的位置进行反注册.
 
4.不关闭输入输出流的话就相当于在内存和硬盘一直存在着连接占用着资源,当其他操作需要资源时就会造成内存溢出.
 
5.位图在安卓中占用的内存是很大的,使用后如果不及时回收的话会占用大量空间,所以针对位图的操作一般有如下解决方案:
1)及时的调用resycle方法来手动的回收;
2)设置采样率,有时候我们不一定要把图片完全显示出来,这时候就要按比例来缩放,在我们得到采样率的时候就可以将图片缩小后再进行加载,节省大量的内存;
3)使用软引用.
 
6.上下文泄露
例如在activity中使用了线程内部类,这时候在线程内存就会保存一个activity的引用,当activity被销毁的时候,线程仍在执行的话就容易造成oom,因为此时的activity的引用仍然存在没有被释放,那么这个activity就仍然没有从内存中被gc.
 
7.static关键字
开发中使用关键字static可以将成员变量和方法变成类变量和类方法,这样会大大延长变量的生命周期,如果我们过多的使用static来保存占用资源过多的对象的引用就会造成内存溢出,比如用static修饰一个上下文的对象的话.
第一,应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。
第二、Context尽量使用Application Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
第三、使用WeakReference代替强引用。比如可以使用WeakReference<Context> mContextRef;
一次解决OOM的经历                             https://segmentfault.com/a/1190000005180612
 (1)  在退出Activity时,把handler的Message和Runnable给干掉
 (2)  Activity context引用不当导致退出时,整个Activity无法回收。程序中尽量使用ApplicationContext
 (3)  检查添加了Listener接口回调后,没有反注册掉
 (4)  List,HashMap等集合类,在退出时clear掉,并置为空
 (5)  单例类中是否引用了ActivityContext

*********************************************************************************************************

 ANR:Application Not Responding,即应用无响应 。ANR产生时, 系统会生成一个traces.txt的文件放在/data/anr/下. 

1. 不要让主线程干耗时的工作2. 不要让其他线程阻塞主线程的执行

1:KeyDispatchTimeout(5 seconds) –主要类型 
按键或触摸事件在特定时间内无响应 
2:BroadcastTimeout(10 seconds) 
BroadcastReceiver 在特定时间内无法处理完成 
3:ServiceTimeout(20 seconds)  
4:非主线程原因
1.CPU满负荷

这个时候你看到的trace信息可能会包含这样的信息:

Process:com.anly.githubapp
...
CPU usage from 3330ms to 814ms ago:
6% 178/system_server: 3.5% user + 1.4% kernel / faults: 86 minor 20 major
4.6% 2976/com.anly.githubapp: 0.7% user + 3.7% kernel /faults: 52 minor 19 major
0.9% 252/com.android.systemui: 0.9% user + 0% kernel
...

100%TOTAL: 5.9% user + 4.1% kernel + 89% iowait
最后一句表明了:
当是CPU占用100%, 满负荷了.
其中绝大数是被iowait即I/O操作占用了.
此时分析方法调用栈, 一般来说会发现是方法中有频繁的文件读写或是数据库读写操作放在主线程来做了.
2.内存原因
其实内存原因有可能会导致ANR, 例如如果由于内存泄露, App可使用内存所剩无几, 我们点击按钮启动一个大图片作为背景的activity, 就可能会产生ANR, 这时trace信息可能是这样的:
// 以下trace信息来自网络, 用来做个示例
Cmdline: android.process.acore

DALVIK THREADS:
"main"prio=5 tid=3 VMWAIT
|group="main" sCount=1 dsCount=0 s=N obj=0x40026240self=0xbda8
| sysTid=1815 nice=0 sched=0/0 cgrp=unknownhandle=-1344001376
atdalvik.system.VMRuntime.trackExternalAllocation(NativeMethod)
atandroid.graphics.Bitmap.nativeCreate(Native Method)
atandroid.graphics.Bitmap.createBitmap(Bitmap.java:468)
atandroid.view.View.buildDrawingCache(View.java:6324)
atandroid.view.View.getDrawingCache(View.java:6178)

...

MEMINFO in pid 1360 [android.process.acore] **
native dalvik other total
size: 17036 23111 N/A 40147
allocated: 16484 20675 N/A 37159
free: 296 2436 N/A 2732

可以看到free的内存已所剩无几.当然这种情况可能更多的是会产生OOM的异常...

哪些地方是执行在主线程的

  1. Activity的所有生命周期回调都是执行在主线程的.
  2. Service默认是执行在主线程的.
  3. BroadcastReceiver的onReceive回调是执行在主线程的.
  4. 没有使用子线程的looper的Handler的handleMessage, post(Runnable)是执行在主线程的.
  5. AsyncTask的回调中除了doInBackground, 其他都是执行在主线程的.
  6. View的post(Runnable)是执行在主线程的.
启动子线程
1. 启Thread方式(继承Thread、实现Runnable接口)
2.使用AsyncTask
3.IntentService
https://blog.csdn.net/a332324956/article/details/77800315
https://blog.csdn.net/yxz329130952/article/details/50087731


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值