一、计算机中的中断和异常
中断又称为硬件中断,是由硬件设备产生的
操作系统的异常是由 操作系统执行某些指令而产生的,这些异常又分为硬件异常和软件异常
1.1 硬件异常:
Windows 识别的硬件异常在下表中进行了汇总:
表 1异常代码异常的原因
STATUS_ACCESS_VIOLATION 读取或写入不可访问的内存位置。
STATUS_BREAKPOINT 遇到硬件定义的断点;仅由调试器使用。
STATUS_DATATYPE_MISALIGNMENT 在没有正确对齐的地址上读取或写入数据;例如,16 位实体必须在 2 字节边界对齐。 (不适用于 Intel 80 x 86 处理器。 )
STATUS_FLOAT_DIVIDE_BY_ZERO 将浮点类型除以 0.0。
STATUS_FLOAT_OVERFLOW 超过浮点类型的最大正指数。
STATUS_FLOAT_UNDERFLOW 超过浮点类型的最小负指数的大小。
STATUS_FLOATING_RESEVERED_OPERAND 使用保留的浮点格式(无效的使用格式)。
STATUS_ILLEGAL_INSTRUCTION 尝试执行处理器未定义的指令代码。
STATUS_PRIVILEGED_INSTRUCTION 执行当前计算机模式下不允许的指令。
STATUS_INTEGER_DIVIDE_BY_ZERO 将整数类型除以 0。
STATUS_INTEGER_OVERFLOW 尝试超出整数的范围的操作。
STATUS_SINGLE_STEP 以单步模式执行一条指令;仅由调试器使用。
上表中列出的很多异常应由调试器、操作系统或其他低级别代码处理。 你的代码不应处理这些错误(整数和浮点错误除外)。 因此,您通常应使用异常处理筛选器来忽略异常(计算结果为 0)。 否则,您可能阻止低级别机制进行适当的响应。 不过,您可以通过 编写终止处理程序来采取适当的预防措施来防范这些低级别错误的潜在影响。
上述数据来源:硬件异常
总结:硬件异常,一部分操作系统会直接处理,不会交由应用程序,一部分会交由应用程序。
1.2 软件异常
系统不会将某些最常见的程序错误源标记为异常。 例如,如果你尝试分配内存块,但没有足够的内存,则运行时或 API 函数不会引发异常,但会返回一个错误代码。
总结:软件异常是进行系统调用时,因调用异常而返回异常值。软件异常,操作系统会返回错误码,交由应用程序进行处理。
其实,到这里,我们能够看到,除了一些严重的错误,如:执行非法指令、调用非法地址等严重异常,操作系统并不会将其交由应用程序,很可能操作系统会选择杀死进程。而对于另一些不是特别严重的异常,并不是我们可不可以处理,而是我们应不应该处理,是不是应该选择让当前执行的线程或进程直接结束,如果打算处理:该怎么处理呢。在下边的Java异常里,我会结合Java异常机制,给出自己浅显的思考。
二Java异常
2.1当我们从Java的角度看待异常,也许会有些许的不同:
0.一个Java应用程序是JVM进程下运行的多个Java线程
1.从Java应该用程序来讲,硬件和操作系统级的异常它只能触及上述提及的部分异常,并选择如何处理。
2.Java基于Java语言层面设计一套异常体系,这套异常体系不仅可以处理来自硬件和操作系统级的异常。还能够处理自定义的和来自JVM
的异常,如(OOM等)。另,处理Java语言层面的自定义异常和来自JVM的异常并不会导致很大的开销。因为他们都只是语言层面编译时的一些小把戏,你甚至可以把 Java异常想象成一个 if 语句,如果条件成立,就会去执行 当前线程的异常链,并没有设计内核态与用户态的切换。(关于异常链,我只能猜测,对它的猜测来自于一篇别人对C++异常设计的思考)。
关于Java 异常机制的设计思想,请参考这篇关于C++异常设计的思想:
C++异常机制的实现方式和开销分析
2.2对异常处理的思考
程序:从某种角度上可以理解为 编译后的机器代码约束着电子器件的运行,使它们得出我们期待的结果。
但是,当执行出了状况就需要操作系统就行抉择,是操作系统直接进行处理,还是交由下层应用程序。仅有少数的几个操作系统级别的异常,操作系统是可以确定自己是具有充分的做出抉择的信息的,如:指令非法、内存越界等。大多数操作系统级别的异常都需要将其交由具有更多运行时信息的应用程序决定如何处理,这时的处理还涉及到内核和用户态的切换。
当异常出现时,我们希望计算机怎么做:
a.终止当前线程或进程,如果异常造成一些数据不一致,我们希望接到异常通知,然后做一些弥补工作,使数据重新回到一致性的状态。这里的一致性包括数据的一致性也包括程序占用资源的关闭
b.继续执行。继续执行包括 1.弥补异常并继续执行 2.重试执行异常语句
2.3对Java完善的异常处理机制的思考(算是猜测吧,是自己的思索)
Java完善的异常体系的意义
Java异常异常捕获体系,通过一个三元组来帮助我们快速定位问题所在地以及帮助我们快速分析问题原因。
当然,这需要我们我们合理的构建程序的异常架构才能发挥出此作用。
三元组
e.printStackTrace() + cause 形成错误链:方便我们定位每一个出错误所在的代码段
打印顺序为,最上层出错误的地方在最前边。下层出错误的地方在最下方
ClassName (错误所在模块),错误类名以类似 Restful的形式命名,方面我们更快的获取关于错误的信息
对运行时错误信息的采集 message
基于以上三者,我们可以拿到: 1.错误在业务逻辑中所处的位置 2.错误出现时的实际代码段 3.代码出错时的运行时信息
这只是我个人的思考,不一定完全正确。
finally执行机制的保证
当异常发生时,不管是否杀死线程,jvm都会保证发生异常的线程的异常链中finally代码块的执行。写好finally代码块能保证JVM存在时线程中打开的一些资源一定会被释放。
如果Java程序被杀死,也即jvm也不存在了,操作系统会保证jvm所占用的资源的释放。
嗯,大致就先写这么多吧!