Error fatal de Java SIGSEGV

Recibo un mensaje de error del compilador de Java que no entiendo. He probado mi código en OSX 10.6, 10.9 y Ubuntu 14.04, con Java 6 y 7. Cuando ejecuto con el depurador Eclipse o desde el intérprete (usando la opción -Xint), todo funciona bien. De lo contrario, recibo los siguientes mensajes:

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
#

Hay más resultados de error para Java 7 (que se guarda en un archivo) pero desafortunadamente no puedo ajustarlo en el límite de caracteres de esta publicación. A veces necesito ejecutar mi código un par de veces para que aparezca el error, pero aparece la mayoría de las veces.

Mi caso de prueba implica el almacenamiento en caché de algunos cálculos en escala logarítmica. Específicamente, dado log (X), log (Y), ..., tengo una clase pequeña que calcula log (X + Y + ...). Y luego guardo en caché el resultado en un HashMap.

Curiosamente, cambiar algunos índices de bucle parece hacer que el problema desaparezca. En particular, si reemplazo

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);
}

entonces no recibo el mensaje de error y el programa funciona bien.

Mi ejemplo mínimo es el siguiente:

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;
        }
    }
}

Respuestas a la pregunta(1)

Su respuesta a la pregunta