关于Error和Exception的一些思考 小结
目录
1. ERROR
2. Exception
2.1 checked Exception
2.2 unchecked Exception
2.3 区别
3. 内存溢出
3.1 堆溢出
3.2 永久代/元空间溢出
3.3 方法栈溢出
Java中,所有的异常都有一个共同的父类:Throwable类。
Throwable类有两个重要的子类:Exception(异常)和Error(错误)。
Exception和Error二者都是Java异常处理的重要子类,各自都包含大量子类,只有Throwable类型的实例才可以被抛出(throw)或捕获(catch)。
1. ERROR
Error属于程序无法处理的错误,是JVM需要负担的责任,无法通过try-catch来进行捕获。
例如,系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复。
如:StackOverFlowError;VirtualMachineError;OutofMemoryError;ThreadDeath。
2. Exception
程序本身可以处理的异常,可以通过catch来进行捕获,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。
Exception又可以分为运行时异常(RuntimeException,又叫非受检查异常unchecked Exception)和非运行时异常(又叫受检查异常checked Exception)。
2.1 checked Exception
在写代码的时候,需要写try catch的Exception,这种Exception一般不会影响主体程序,可以由程序员手动诊断修复异常。
如:IOException;SQLException;ClassNotFoundException。
2.2 unchecked Exception
又称RunTimeException,这一类就是在代码处理了checked Exception之后,运行时候仍然会遇到的Exception。
如:NullPropagationException;ClassCastException;ArithmeticException;IllegalArgumentException;IndexOutOfBoundsException(包括ArrayIndexOutofBoundsExcpetion;StringIndexOutofBoundsExcpetion);NumberFormatException。
2.3 区别
1) Checked Exception 的基类是 Exception,
Runtime Exception 的基类是 RuntimeException
( RuntimeException
的父类也是 Exception
)。
2) Checked Exception 要求必须捕获,一个方法内如果抛出了 Checked Exception,必须要么 catch,
要么给方法声明 throws
以交给上一层去处理,如果漏写了 catch
会直接通不过编译。 Runtime Exception 就没这个要求,不强制 catch
或 throws,
这样对于明显不会异常的代码段就不必处理了。
3. 内存溢出
3.1 堆溢出
java.lang.OutOfMemoryError: Java heap space
1) 原因。
- 代码中可能存在大对象分配。
- 可能存在内存泄露,导致在多次GC之后,还是无法找到一块足够大的内存容纳当前对象。
2) 解决方法。
- 检查是否存在大对象的分配,最有可能的是大数组分配。
- 通过jmap命令把堆内存保存下来,使用mat工具分析检查是否存在内存泄露的问题。
- 如果没有找到明显的内存泄露,使用 -Xmx 加大堆内存。
- 检查是否有大量的自定义的 Finalizable 对象,也有可能是框架内部提供的,考虑其存在的必要性。
3.2 永久代/元空间溢出
java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError: Metaspace
1) 原因。永久代是 HotSot 虚拟机对方法区的具体实现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。JDK8后,元空间替换了永久代,元空间使用的是本地内存,字符串常量由永久代转移到堆中,可能原因有如下几种:
- 在Java7之前,频繁的错误使用String.intern()方法。
- 运行期间生成了大量的代理类,导致方法区被撑爆,无法卸载。
- 应用长时间运行,调试时没有重启 JVM。
2) 解决方法。
- 检查是否永久代空间或者元空间设置的过小。
- 检查代码中是否存在大量的反射操作。
- 通过mat检查是否存在大量由于反射生成的代理类。
- 重启JVM。
3.3 方法栈溢出
java.lang.OutOfMemoryError : unable to create new native Thread
1) 原因。
- 出现这种异常,基本上都是创建了大量线程导致的。
2) 解决方法。
- 通过 -Xss 降低的每个线程栈大小的容量。
- 线程总数也受到系统空闲内存和操作系统的限制,检查是否该系统下有此限制:/proc/sys/kernel/pid_max/proc/sys/kernel/thread-maxmaxuserprocess(ulimit -u)/proc/sys/vm/maxmapcount