Ricevo un messaggio di errore dal compilatore Java che non capisco. Ho testato il mio codice su OSX 10.6, 10.9 e Ubuntu 14.04, con Java 6 e 7. Quando corro con il debugger Eclipse o dall'interprete (usando l'opzione -Xint), tutto gira bene. In caso contrario, ottengo i seguenti messaggi:Errore irreversibile Java SIGSEGV
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
#
C'è di più output di errore per Java 7 (che viene salvato in un file), ma purtroppo ho non può adattarsi nel limite di caratteri di questo post. A volte ho bisogno di eseguire il mio codice un paio di volte per l'errore, ma appare più spesso.
Il mio caso di test comporta l'archiviazione in cache di alcuni calcoli in scala logaritmica. Specificamente, dato log (X), log (Y), ..., ho una piccola classe che calcola log (X + Y + ...). E poi memorizzo il risultato in una HashMap.
Stranamente, la modifica di alcuni indici di loop sembra far sì che il problema scompaia. In particolare, se sostituisco
for (int z = 1; z < x+1; z++) {
double logSummand = Math.log(z + x + y);
toReturn.addLogSummand(logSummand);
}
con
for (int z = 0; z < x; z++) {
double logSummand = Math.log(1 + z + x + y);
toReturn.addLogSummand(logSummand);
}
allora non ho ricevuto il messaggio di errore e il programma funziona bene.
Il mio esempio minimo è qui sotto:
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;
}
}
}
Questo probabilmente non è un bug nel programma (i semplici programmi Java non dovrebbero mai causare un errore di segmentazione). Potrebbe essere un bug nel tuo hardware o nella tua implementazione di jvm. Prova un controllo completo della memoria e prova una macchina diversa. – Fabian
Ho sempre riscontrato questo errore esatto quando scrivevo codice nativo (C, C++, ecc.) Tramite JNI. Stai usando il codice nativo (non mostrato nella domanda) o è davvero tutto Java? Come già sottolineato, Java puro non dovrebbe mai causare un segfault. – Radiodef
Dopo aver eseguito il codice, ottengo anche un errore di segmentazione con "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, modalità mista) ". – Fabian