예외

프로그램 실행 도중 CPU가 감지하는 비정상적인 상황으로, 동기적으로 발생하는 소프트웨어 인터럽트의 한 종류입니다.

예외의 3가지 분류

분류설명복귀 지점예시
Fault복구 가능, 원인 해결 후 해당 명령어 재실행오류 발생 명령어페이지 폴트, 세그먼트 부재
Trap정상 처리 후 다음 명령어로 진행다음 명령어디버그 브레이크포인트, 오버플로우
Abort복구 불가능한 심각한 오류복귀 불가이중 폴트(Double Fault), 하드웨어 오류
예외 (Exception)
  │
  ├── Fault ──── 복구 가능 → 같은 명령어 재실행
  │    ex) 페이지 폴트: 디스크에서 페이지 로드 후 재실행
  │
  ├── Trap ───── 정상 → 다음 명령어로 진행
  │    ex) int 3 브레이크포인트: 디버거에 제어 넘긴 후 계속
  │
  └── Abort ──── 복구 불가 → 프로세스/시스템 종료
       ex) Double Fault: 예외 처리 중 또 예외 발생

예외 vs 트랩 vs 하드웨어 인터럽트

항목예외트랩 (시스템 콜)하드웨어 인터럽트
발생 원인프로그램 오류·비정상 상황프로그래머의 의도적 요청외부 장치 이벤트
동기/비동기동기적동기적비동기적
의도성비의도적의도적비의도적
예시0으로 나누기, 페이지 폴트read(), fork()키보드, 타이머

x86 주요 예외 벡터

벡터이름분류설명
0Divide ErrorFault0으로 나누기
1DebugTrap/Fault디버그 예외
3BreakpointTrapint 3 브레이크포인트
6Invalid OpcodeFault잘못된 명령어
8Double FaultAbort예외 처리 중 또 예외
11Segment Not PresentFault세그먼트 미존재
12Stack-Segment FaultFault스택 세그먼트 오류
13General Protection FaultFault권한 위반, 잘못된 메모리 접근
14Page FaultFault페이지 미존재

페이지 폴트 처리 흐름 (Fault 예시)

① 프로그램이 가상 주소 접근
② MMU가 페이지 테이블 확인 → 물리 메모리에 없음
③ Page Fault 예외 발생 (벡터 14)
④ CPU → IDT[14] → Page Fault 핸들러 실행
⑤ 커널이 디스크에서 해당 페이지를 메모리에 로드
⑥ 페이지 테이블 갱신
⑦ 원래 명령어 재실행 (Fault이므로 같은 명령어로 복귀)
프로그램: arr[1000] 접근
    │
    ▼
 MMU: 페이지 없음! → Page Fault
    │
    ▼
 커널: 디스크 → 메모리 로드, 페이지 테이블 갱신
    │
    ▼
 프로그램: arr[1000] 재실행 → 이번엔 성공

Double Fault / Triple Fault (Abort 예시)

예외 발생 → 핸들러 실행 시도
    │
    ├── 핸들러 정상 실행 → 복구 완료
    │
    └── 핸들러 실행 중 또 예외 발생
         │
         ├── Double Fault (벡터 8) → 별도 핸들러로 처리 시도
         │        │
         │        └── 여기서도 예외 발생
         │              │
         │              └── Triple Fault → CPU 리셋 (재부팅)
         │
         └── 복구 불가 → 프로세스 또는 시스템 종료

Java 예외와 CPU 예외의 관계

Java의 예외(Exception)와 CPU 예외는 다른 개념이지만, 일부 Java 예외는 CPU 예외에서 비롯됩니다.

CPU 예외Java 예외설명
Divide Error (벡터 0)ArithmeticException0으로 나누기
Page Fault (벡터 14)-JVM이 내부적으로 처리 (사용자에게 노출 안 됨)
General Protection Fault (벡터 13)NullPointerExceptionnull 참조 접근 시 JVM이 변환
-ArrayIndexOutOfBoundsExceptionJVM 자체 경계 검사 (CPU 예외 아님)
Stack-Segment Fault (벡터 12)StackOverflowError스택 오버플로우
// CPU 예외 → JVM이 Java 예외로 변환
try {
    int result = 10 / 0;         // CPU: Divide Error (벡터 0)
} catch (ArithmeticException e) { // JVM이 ArithmeticException으로 변환
    System.out.println("0으로 나눌 수 없습니다");
}

try {
    Object obj = null;
    obj.toString();              // CPU: GPF 또는 SIGSEGV
} catch (NullPointerException e) { // JVM이 NullPointerException으로 변환
    System.out.println("null 참조");
}

// JVM 자체 검사 (CPU 예외가 아닌 경우)
try {
    int[] arr = new int[3];
    arr[10] = 5;                 // JVM이 배열 경계 직접 검사
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("배열 범위 초과");
}

Java 예외 vs CPU 예외 처리 흐름 비교

[CPU 예외 처리]
오류 발생 → CPU가 감지 → IDT 조회 → 커널 핸들러 실행 → 시그널 전달

[Java 예외 처리 - CPU 예외 기반]
오류 발생 → CPU 예외 → 커널 → SIGSEGV/SIGFPE 시그널
→ JVM 시그널 핸들러 → Java Exception 객체 생성 → catch 블록

[Java 예외 처리 - JVM 자체 검사]
오류 조건 감지 → JVM이 직접 Exception 객체 생성 → catch 블록
(CPU 예외 없이 JVM 레벨에서 처리)

CSLOG에서 보기