Java fatal error SIGSEGV mit keine zusätzlichen nativen code

Erhalte ich eine Fehlermeldung aus der Java-compiler, dass ich nicht verstehe. Ich habe getestet, mein code auf OSX 10.6, 10.9 und Ubuntu 14.04, mit Java 6 und 7. Wenn ich mit dem Eclipse-debugger oder den interpreter (mit -Xint option), läuft alles einwandfrei. Andernfalls erhalte ich die folgenden Meldungen:

Java 1.6:

Invalid memory access of location 0x8 rip=0x1024e9660

Java 1.7:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x000000010f7a8262, pid=20344, tid=18179
#
# JRE version: Java(TM) SE Runtime Environment (7.0_60-b19) (build 1.7.0_60-b19)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.60-b09 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.dylib+0x3a8262]  PhaseIdealLoop::idom_no_update(Node*) const+0x12
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

Es gibt noch mehr Fehler-Ausgabe für Java 7 (das ist in einer Datei gespeichert), aber leider kann ich nicht, es passt in die Zeichen-Grenze von diesem post.
Manchmal muss ich meinen code ein paar mal für den Fehler zu kommen, aber es scheint mehr als oft nicht.

Meinem test-Fall ist Cachen einige Berechnungen in logarithmischer Skala. Speziell, da log(X),log(Y),..., habe ich eine kleine Klasse berechnet, dass log(X+Y+...). Und dann habe ich cache das Ergebnis in einer HashMap.

Seltsam, ändert einige loop-Indizes scheint das problem Weg. Insbesondere, wenn ich ersetzen

for (int z = 1; z < x+1; z++) {
    double logSummand = Math.log(z + x + y);
    toReturn.addLogSummand(logSummand);
}

mit

for (int z = 0; z < x; z++) {
    double logSummand = Math.log(1 + z + x + y);
    toReturn.addLogSummand(logSummand);
}

dann bekomme ich keine Fehlermeldung und das Programm läuft wunderbar.

Mein minimal-Beispiel ist unter:

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TestLogSum {
    public static void main(String[] args) {

        for (int i = 0; i < 6; i++) {
            for (int n = 2; n < 30; n++) {
                for (int j = 1; j <= n; j++) {
                    for (int k = 1; k <= j; k++) {
                        System.out.println(computeSum(k, j));                       
                    }
                }
            }
        }
    }

    private static Map<List<Integer>, Double> cache = new HashMap<List<Integer>, Double>();
    public static double computeSum(int x, int y) {     
        List<Integer> key = Arrays.asList(new Integer[] {x, y});

        if (!cache.containsKey(key)) {

            //explicitly creating/updating a double[] array, instead of using the LogSumArray wrapper object, will prevent the error
            LogSumArray toReturn = new LogSumArray(x);

            //changing loop indices will prevent the error
            //in particular, for(z=0; z<x-1; z++), and then using z+1 in place of z, will not produce error
//         for (int z = 0; z < x; z++) {
//             double logSummand = Math.log(1 + z + x + y);
            for (int z = 1; z < x+1; z++) {
                double logSummand = Math.log(z + x + y);
                toReturn.addLogSummand(logSummand);
            }

            //returning the value here without cacheing it will prevent the segfault
            cache.put(key, toReturn.retrieveLogSum());
        }
        return cache.get(key);
    }

    /*
     * Given a bunch of logarithms log(X),log(Y),log(Z),...
     * This class is used to compute the log of the sum, log(X+Y+Z+...)
     */
    private static class LogSumArray {      
        private double[] logSummandArray;
        private int currSize;

        private double maxLogSummand;

        public LogSumArray(int maxEntries) {
            this.logSummandArray = new double[maxEntries];

            this.currSize = 0;
            this.maxLogSummand = Double.NEGATIVE_INFINITY;
        }

        public void addLogSummand(double logSummand) {
            logSummandArray[currSize] = logSummand;
            currSize++;
            //removing this line will prevent the error
            maxLogSummand = Math.max(maxLogSummand, logSummand);
        }

        public double retrieveLogSum() {
            if (maxLogSummand == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY;

            assert currSize <= logSummandArray.length;

            double factorSum = 0;
            for (int i = 0; i < currSize; i++) {
                factorSum += Math.exp(logSummandArray[i] - maxLogSummand);
            }

            return Math.log(factorSum) + maxLogSummand;
        }
    }
}
  • Das ist wahrscheinlich kein bug in deinem Programm (simple java-Programme sollten nie dazu führen, einen "segmentation fault"). Es könnte ein Fehler in Ihrer hardware oder Ihren jvm-Implementierung. Versuchen Sie eine vollständige Speicher prüfen und zu versuchen, eine andere Maschine.
  • Ich habe immer nur auf genau diesem Fehler beim schreiben von nativen code (C, C++, etc) über JNI. Sind Sie mit systemeigenem code (nicht gezeigt in der Frage) oder ist es wirklich alles Java? Wie schon bereits, Reine Java sollte nie dazu führen, einen segfault.
  • Nach ausführen des Codes, bekomme ich auch einen segmentation fault mit "java-version "1.7.0_55" OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-2) OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)".
  • Radiodef, ich bin nicht über eine native code, es ist alles Java. Fabian, danke für die Bestätigung, dass dies geschieht, wird auf Ihrem Rechner/setup-als auch.
  • Dies löst eine jvm-Fehler, die auf java 1.7.0_51 aber nicht auf 1.8.0_05 auf windows 7 x64. Haben Sie versucht, mit dem flag-XX:-PartialPeelLoop", denn es sind ähnliche Fehler gemeldet und die Flagge ist eigentlich "überspringen", die problematisch compiler code. Suche für PhaseIdealLoop::idom_no_update
  • Ich traf so ziemlich den gleichen Fehler beim spielen mit einer rekursiven Java-Programm einmal.
  • Ich habe versucht -XX:-PartialPeelLoop für Java SE 7 auf OSX 10.9 und es bricht immer noch. Ich habe auch versucht flag -XX:-UseLoopPredicate, die nicht fix das minimale Testfall, aber schien zu verhindern, dass der Fehler in einem anderen größeren Projekt. (sorry für das löschen und Wiedereinstellen mit dieser Bemerkung wollte ich zum Bearbeiten ein paar Dinge, die in es)
  • Ich denke, das sollte gemeldet werden Oracle. Dieser code ist nichts super besonderes, und trotzdem bricht es. Auch auf meinem Rechner.

InformationsquelleAutor jackkamm | 2014-06-07
Schreibe einen Kommentar