2011-11-21 7 views
6

は、私は非常に単純なCプログラムを書いた:Javaでは、 "5/0"ステートメントはLinuxマシンでSIGFPEシグナルを発しません、なぜですか?

#include<stdio.h> 

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

をし、straceのとそれを実行します。

... ... 
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 

は出力が一致した(のみ貼り付ける尾部)straceのを./a.outと出力の下に取得する私のそれは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のジャワ-Xcompメイン

... ... 
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) 
+0

そこには浮動小数点はありませんが。なぜ浮動小数点信号を期待していますか?そしてあなたの 'C'コードは本当にintを使用しましたか? – EJP

+2

Javaレベルの例外がありますか? DivisionByZeroExceptionまたは何か。それは十分ではないですか?あなたは、JVMがプロセッサーとどのように話し合っているか興味を持っていますか? – Thilo

+1

おそらく私は何かを見逃していますが、あなたはJavaでDivideByZeroExceptionをキャッチしませんか? – Gaff

答えて

7

ここで、SIGFPEを発生させます。

straceに子供を追跡することを忘れました。 strace-fオプションを追加すると、のようなものが表示されるはずです。

[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 
1

のJavaプログラムからハードウェアを抽象化する仮想マシン(JVM)で実行されます。 JavaプログラムのほとんどのエラーはJava例外を引き起こし、ネイティブのCPUまたはOSエラーコードをトリガーしません。私はこのコードがArithmeticException(またはそのようなもの)をスローすると思います。

+1

はい、それはArithmeticExceptionをスローしますが、どうですか? – zhangfaen

5

(通常の)Cコンパイルプログラムとは対照的に、Javaプログラムはプロセッサではなく実行時に実行され、プラットフォームに依存しません。 Javaでゼロで割ると、このようにはArithmeticExceptionをトリガー:

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

JLSから:

例外が3つのいずれかの理由でスローされます。異常な実行 状態が同期で検出された

Java仮想マシン。 15.6

にまとめたように、エラーが負荷の発生または一部を連結式の

評価は、ゼロによって、整数除算のような言語の 通常のセマンティクスを、違反、 :そのような 条件があるために生じます プログラム(§12.2、§12.3)

リソース上のいくつかの制限が そのような大量のメモリを使用するものとして、超過し

+1

Hmm .. Javaプログラムはランタイムで動作しますが、最終的にはプロセッサ上で動作します。さらに、パラメータ "-Xcomp"を追加しました。つまり、JITはすべてのメソッドをローカルプロセッサの命令にコンパイルする必要があります。さらに、両方のプログラムがLinux上で動作するので、両方ともSIGFPEシグナルを発生させることが期待されます。 – zhangfaen

+0

それは本当ですが、私が間違っていないと、そのようなことは実行前にランタイムによってチェックされます。 – MByD

+0

実行前に0をチェックすることは非常にコストがかかりますが、VMはそのことをしないと思います。 – zhangfaen

2

VMはエミュレートされたバイトコード(実装を簡単にするため)で除数を手動で0としてテストするかもしれませんが、パフォーマンスは依然としてJITコード内のSIGFPE信号の検出に切り替わります。除算コードを独自のサブルーチンに入れて、それがコンパイルされることを確実にするために何千回もループさせてみてください。

+0

が試行されましたが、SIGFPEは発生しません。 IMHOは、毎回VMテストの除数が0であるとは思わないので、明らかに無駄です。 – zhangfaen

+0

@zhangfaen: '-XX:+ PrintOptoAssembly'モードを試してください。参照してください:http://stackoverflow.com/questions/1551781/how-can-i-see-the-code-that-hotspot-generates-after-optimizing – Boann

+0

これは答えではありません。 –

0

がJavaにあります。用語例外は、フレーズの「例外的なイベント」の略語です。
例外は、プログラムの実行中に発生し、プログラムの命令の通常の流れを妨げるイベントです。
メソッド内でエラーが発生すると、このメソッドはオブジェクトを作成し、それをランタイムシステムに渡します。例外オブジェクトと呼ばれるオブジェクトには、エラーの種類と、エラーが発生したときのプログラムの状態など、エラーに関する情報が含まれています。例外オブジェクトを作成し、それをランタイムシステムに渡すことは、例外をスローすることと呼ばれます。 Javaでゼロ除算
uはその例外をキャッチした場合、その後uはuは例外をキャッチした後に何をしたいのか行うことができますが、それ以外の場合は、エラー情報が表示され、デフォルトのハンドラによって処理し、プログラムを終了している...
ははArithmeticExceptionとして作ります

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

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()を参照してください(複数のスレッドを実行するか、を行いますjavaが実行されているとき)、straceの出力が不完全になります。

もう少し詳しく説明すると、未処理のSIGFPEは、プログラムでエラーが発生したことを示します。 javaがSIGFPEによって殺された場合、JVM内で実行されているエラーではなく、JVM内で実行されているアプリケーションでエラーが発生していることを示します。

+0

クール、ありがとう! – zhangfaen

関連する問題