Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
(1). Throwable
Throwable是 Java 语言中所有错误或异常的超类。
Throwable包含两个子类: Error 和 Exception 。它们通常用于指示发生了异常情况。
Throwable包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息。
(2). Exception
Exception及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
(3). RuntimeException
RuntimeException是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。
编译器不会检查RuntimeException异常。 例如,除数为零时,抛出ArithmeticException异常。RuntimeException是ArithmeticException的超类。当代码发生除数为零的情况时,倘若既”没有通过throws声明抛出ArithmeticException异常”,也”没有通过try…catch…处理该异常”,也能通过编译。这就是我们所说的”编译器不会检查RuntimeException异常”!
如果代码会产生RuntimeException异常,则需要通过修改代码进行避免。 例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!
(4). Error
和Exception一样, Error也是Throwable的子类。 它用于指示合理的应用程序不应该试图捕获的严重问题,大多数这样的错误都是异常条件。
和RuntimeException一样, 编译器也不会检查Error。
Java将可抛出(Throwable)的结构分为三种类型: 被检查的异常(Checked Exception),运行时异常(RuntimeException)和错误(Error)。
(01) 运行时异常
定义 : RuntimeException及其子类都被称为运行时异常。
特点 : Java编译器不会检查它。 也就是说,当程序中可能出现这类异常时,倘若既”没有通过throws声明抛出它”,也”没有用try-catch语句捕获它”,还是会编译通过。例如,除数为零时产生的ArithmeticException异常,数组越界时产生的IndexOutOfBoundsException异常,fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常。
虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。
如果产生运行时异常,则需要通过修改代码来进行避免。 例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!
(02) 被检查的异常
定义 : Exception类本身,以及Exception的子类中除了”运行时异常”之外的其它子类都属于被检查异常。
特点 : Java编译器会检查它。 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。例如,CloneNotSupportedException就属于被检查异常。当通过clone()接口去克隆一个对象,而该对象对应的类没有实现Cloneable接口,就会抛出CloneNotSupportedException异常。
被检查异常通常都是可以恢复的。
(03) 错误
定义 : Error类及其子类。
特点 : 和运行时异常一样,编译器也不会对错误进行检查。
当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复这些错误的。例如,VirtualMachineError就属于错误。
按照Java惯例,我们是不应该是实现任何新的Error子类的!
学习《深入理解Java虚拟机 JVM高级特性域最佳实践》,学习到了JVM中常见的OutOfMemory和StackOverFlow产生的机理,感觉非常有用。
1.平时代码运行时遇到这两种错误后就可以根据具体情况去适时地调整JVM参数来处理问题
2.平时写代码的时候也会多加注意,不要让代码产生这两种异常
下面就记录下,当作学习笔记。
首先必须了解JVM运行时数据区域
方法区
用于存储已被JVM加载的类信息,常量,静态变量,即时编译器编译后的代码,线程共享。
运行时常量池
方法区一部分。存放编译期生成的各种字面量和符号引用。
虚拟机栈
内部创建栈帧,来存放局部变量表,操作数栈,动态链接,方法出口等,线程私有。
本地方法栈(HotSpot不区分虚拟机栈和本地方法栈)
类似虚拟机栈,但是只为Native方法服务。
堆
存放实例对象和数组,线程共享。
程序计数器
存放当前线程执行的字节码的行号。
1.产生堆溢出
堆是存放实例对象和数组的地方,当对象多过设置的堆大小,同时避免GC回收即可。最大内存块Xmx和最小内存块Xms一样,堆就不可扩展了。将new出的对象放到List中可防止GC回收。
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/*
* VM args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* Xms equals Xmx lead to head value can't extend
*/
import java.util.ArrayList;
import java.util.List;
public class HeapOOM {
static class OOMObject {
}
public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
while (true) {
list.add(new OOMObject());
}
}
}
2.产生虚拟机栈或本地方法栈StackOverFlow
当请求的栈深度超过JVM允许最大深度即可,用Xss设置
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/*
*VM args: -Xss128K
*/
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak() {
stackLength++;
stackLeak();
}
public static void main(String[] args) throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch(Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
3.产生虚拟机栈或方法栈OutOfMemory
不断创建线程
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/*
* VM args: -Xss2M
*/
public class JavaVMStackOOM {
private void dontStop() {
while (true) {
}
}
public void stackLeakByThread() {
while (true) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String[] args) {
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeakByThread();
}
}
4.运行时常量池异常
使用String.interm()填充常量池。intern的左右是如果该常量不再常量池中,则添加到常量池,否则返回该常量引用。常量池是方法区一部分,运行时可限制方法区PermSize和最大方法区MaxPermSize大小
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/*
* VM args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
import java.util.List;
import java.util.ArrayList;
public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
//keep reference,avoid GC collect
List<String> list = new ArrayList<String>();
//10M PermSize in integer range enough to lead to OOM
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}
5.方法区溢出
通过CGLib将大量信息放到方法区
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/*
* VM args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class JavaMethodAreaOOM {
public static void main(String[] args) {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
enhancer.create();
}
}
static class OOMObject() {
}
}