В java оператор «5/0» не запускает сигнал SIGFPE на моей машине с Linux, почему? - PullRequest
6 голосов
/ 21 ноября 2011

Я написал очень простую программу на c:

#include<stdio.h>

int main(){
    int a=2;
    int b=0;
    printf("%d\n", a/b);
}

и запустите его с помощью strace: strace ./a.out и получите результат ниже (только вставьте хвостовую часть)

... ...
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f04c7fb8000, 4096, PROT_READ) = 0
munmap(0x7f04c7f96000, 127640)          = 0
--- SIGFPE (Floating point exception) @ 0 (0) ---
+++ killed by SIGFPE +++
Floating point exception

Вывод соответствует моему ожиданию, так как он был прерван сигналом SIGFPE.

Однако та же самая программа, написанная на Java, не получает сигнал SIGFPE, кто-нибудь знает, как java-процессы "делят на ноль" исключение?

public class Main {

  public static void main(String[] args) {
    int a = 2;
    int b = 0;
    System.out.println(a / b);
  }
}

strace java -Xcomp Main

... ...
mprotect(0xf6949000, 8171520, PROT_READ|PROT_WRITE) = 0
mprotect(0xf6949000, 8171520, PROT_READ|PROT_EXEC) = 0
munmap(0xf774f000, 5727)                = 0
mmap2(NULL, 331776, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0xfffffffff68d0000
mprotect(0xf68d0000, 4096, PROT_NONE)   = 0
clone(child_stack=0xf6920494, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xf6920bd8, tls=0xf6920bd8, child_tidptr=0xff9c5520) = 958
futex(0xf6920bd8, FUTEX_WAIT, 958, NULL) = 0
exit_group(0)  

Ответы [ 6 ]

8 голосов
/ 22 ноября 2011

Здесь поднимается SIGFPE.

Вы забыли сказать strace следовать за детьми. Добавьте параметр -f к strace, и вы должны увидеть что-то похожее на:

[pid  2304] read(3, "\312\376\272\276\0\0\0001\0n\n\0\23\0I\t\0\3\0J\7\0K\n\0L\0M\n\0N\0"..., 2369) = 2369
[pid  2304] --- SIGFPE (Floating point exception) @ 0 (0) ---
[pid  2304] rt_sigreturn(0x1c50800)     = 5
[pid  2304] write(2, "Exception in thread \"main\" ", 27Exception in thread "main" ) = 27
[pid  2304] write(2, "java.lang.ArithmeticException: /"..., 40java.lang.ArithmeticException: / by zero) = 40
[pid  2304] write(2, "\n", 1
5 голосов
/ 21 ноября 2011

Очевидно, это потому, что JVM имеет что-то подобное в своем коде:

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void fpe_handler(int signum) {
  printf("JVM throws an ArithmeticException here...\n");
  exit (1);
}

int main() {
  int a = 5;
  int b = 0;
  signal(SIGFPE, fpe_handler);
  printf("%d\n", a / b);
  return 0;
}

Также JVM запускает несколько потоков (см. clone() в журнале выше или выполните ps -eLf, когда java работает)вывод этой строки просто неполный.

Если немного подробнее, необработанный SIGFPE указывает на ошибку в программе, в которой она произошла.И если SIGFPE уничтожит Java, это будет означать, что ошибка в JVM, но не в вашем приложении, работающем внутри JVM.

5 голосов
/ 21 ноября 2011

В отличие от (обычной) программы компиляции C, Java-программа выполняется во время выполнения, а не на процессоре, и не зависит от платформы. Деление на ноль в Java запускает ArithmeticException, как это:

Exception in thread "main" java.lang.ArithmeticException: / by zero

С JLS :

Исключение выдается по одной из трех причин:

ненормальное исполнение условие было синхронно обнаружено виртуальной машиной Java. такие условия возникают из-за:

оценка выражения нарушает нормальная семантика языка, такая как целочисленное деление на ноль, как описано в §15.6

ошибка при загрузке или связывании части программа (§12.2, §12.3)

превышено некоторое ограничение на ресурс, например, использование слишком большого объема памяти

2 голосов
/ 21 ноября 2011

Возможно, что VM вручную проверяет делитель на 0 в эмулируемом байт-коде (для простоты реализации), но для производительности все равно переключится на обнаружение сигнала SIGFPE в коде JIT.Попробуйте поместить код деления в свою собственную подпрограмму и вызывать его в цикле тысячи раз, чтобы убедиться, что он скомпилирован.

1 голос
/ 21 ноября 2011

Java работает на виртуальной машине (JVM), которая абстрагирует оборудование от программы. Большинство ошибок в Java-программе приводят к исключениям Java и не вызывают никаких собственных кодов ошибок процессора или ОС. Я предполагаю, что этот код вызовет исключение ArithmeticException (или что-то в этом роде).

0 голосов
/ 21 ноября 2011

в Java есть термин исключение - сокращение от фразы «исключительное событие».
Исключением является событие, которое происходит во время выполнения программы и нарушает нормальный поток инструкций программы.
Когда в методе возникает ошибка, метод создает объект и передает его в систему времени выполнения. Объект, называемый объектом исключения, содержит информацию об ошибке, включая ее тип и состояние программы на момент возникновения ошибки. Создание объекта исключения и его передача в систему времени выполнения называется генерацией исключения.
если вы перехватываете это исключение, то вы можете делать то, что хотите, после перехвата исключения, в противном случае он обрабатывается обработчиком по умолчанию, который показывает информацию об ошибке и завершает программу ... Деление на ноль в java make как ArithmeticException

Exception in thread "main" java.lang.ArithmeticException: / by zero 
...