exception StackOverflowError

exception StackOverflowError - Java - Programmation

Marsh Posté le 03-03-2004 à 11:36:13    

Bonjour,
 
j'ai un probleme avec une fonction reccursive.
Le code s'exécute mais, il arrive un moment où l'exception  
StackOverflowError est levée. Je me demande si cette erreur n'est pas liée à la mémoire virtuel.
 
Le code est le suivant :
private void getPartImage(int cSel,int x,int y,int w,int h) {
   
  int yy,xx;
  xx = x + 1;
  yy = y;
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
   }
  }
   
  xx = x + 1;
  yy = y - 1;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
     
    getPartImage(cSel,xx,yy,w,h);
     
     
   }
  }
 
  xx = x;
  yy = y - 1;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
     
     
   }
  }
   
  xx = x - 1;
  yy = y - 1;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
   }
  }
   
  xx = x - 1;
  yy = y ;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
 
   }
  }
   
  xx = x - 1;
  yy = y + 1;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
     
   }
  }
   
  xx = x ;
  yy = y + 1 ;
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
 
   }
  }
   
  xx = x + 1;
  yy = y + 1;
 
   
  if (xx < w && yy < h && yy >=0 && xx >= 0) {
   if (iPix[yy * w + xx] == cSel) {
    iPix[yy * w + xx] = -255;
    vPix.add(new Dimension(xx,yy));
    getPartImage(cSel,xx,yy,w,h);
         
   }
  }  
   
   
 }
 
Le principe est de délimiter une zone de mon tableau dont les valeurs sont identiques et délimités par des valeurs différentes dans le tableau.
Si quelqu'un pouvait m'indiquer m'aider sur ce pb Merci

Reply

Marsh Posté le 03-03-2004 à 11:36:13   

Reply

Marsh Posté le 03-03-2004 à 12:13:22    

J'ai pas lu le code de ta méthode (trop longue à mon gout) mais une chose est sure : c'est la condition d'arrêt de la récursivité qui n'arrête pas le traitement.
 
normalement, on fait ça avec l'algorithme du peintre, qu'on dérécursivise (en utilisant une pile explicite) pour des raisons de lisibilité.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 03-03-2004 à 12:24:59    

Disons que le code est un gros brouillon. Normalement la fonction doit s'arrêter forcément à un moment donné par contre le nombre d'appel doit être supérieur à une limite qui déclenche une exception.
J'ai fait un test avec la fonction void essai() { it++ ; if (it<50000) { essai(); } }  
 
ca plante par contre avec it < 500, ca marche.

Reply

Marsh Posté le 03-03-2004 à 12:43:33    

quelle est la taille du tableau iPix ?
 
D'une manière générale, ce n'est *jamais* en raison de la taille des données mais en raison d'un bug qu'on a ce genre d'erreur. En particulier quand on a un code aussi dégueulasse.


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 03-03-2004 à 15:06:03    

ce n'est pas à mon avis en terme de taille de données mais plutôt d'itérations.

Reply

Marsh Posté le 04-03-2004 à 11:18:02    

Par construction, la pile d'appels n'est pas infinie.
 
Pour confirmer/infirmer tes dires, j'ai fait un petit test rapide :

Code :
  1. public class StackOverflow {
  2.   public static void main(String[] args) {
  3.     StackOverflow  so = new StackOverflow();
  4.     try {
  5.       so.recursive();
  6.     }
  7.     catch (StackOverflowError e) {
  8.       System.err.println("StackOverflowError levée après " + so.numAppels + " appels." );
  9.     }
  10.   }
  11.   private int numAppels = 0;
  12.   public void recursive() {
  13.     this.numAppels++;
  14.     this.recursive();
  15.   }
  16. }


Et voici le résultat sur ma machine (avec Java HotSpot(TM) Client VM (build 1.3.1_09-b03, mixed mode) :

StackOverflowError levée après 17719 appels.


 
Ce qui confirme que la récursivité n'est pas faite pour des millers d'appels récursifs, seulement quelques dizaines ou quelques centaines. Au-delà, comme le dit nraynaud, il faut dérécursifier en utilisant sa propre pile.
 
Et au passage, factoriser ton code serait aussi une très bonne idée (ton double "if" existe en huit exemplaires !). Du genre :

Code :
  1. private void getPartImage(int cSel, int x, int y, int w, int h) {
  2.   for (int ii = -1; ii <= 1; ii++) {
  3.     for (int jj = -1; jj <= 1; jj++) {
  4.       if (ii != 0  &&  jj != 0) {
  5.         int  xx = x + ii;
  6.         int  yy = y + jj;
  7.         if (xx < w  &&  yy < h  &&  yy >=0  &&  xx >= 0) {
  8.           if (iPix[yy * w + xx] == cSel) {
  9.             iPix[yy * w + xx] = -255;
  10.             vPix.add(new Dimension(xx, yy));
  11.             this.getPartImage(cSel, xx, yy, w, h);
  12.           }
  13.         }
  14.       }
  15.     }
  16.   }
  17. }


 
Un tel code est déjà beaucoup plus lisible, beaucoup plus facile à maintenir que ton code initial (et pourtant, il est strictement équivalent pour la machine). Et il sera beaucoup plus facile à dérécursifier.

Reply

Marsh Posté le 05-03-2004 à 21:35:37    

rehello,
 
Je suis tous à fait d'accord avec toi BifaceMcLeOD. J'ai fait ce code en quelques minutes pour essayer de voir si ça fonctionnait.
Les performances de la machine ne sont d'ailleurs pas mise à contribution par rapport à un code plus propre. J'ai l'intention de coder proprement les méthodes.
Par contre, j'essaye de résoudre le pb technique ce qui m'énerve de + en +.
J'ai essayer sous forme d'applet un code équivalent un peu comme celui proposé précédemment et il n'y a pas de souci. Par contre, sous forme d'appli ca plante.
 
Il y a une exception levée pour les fonctions récursives trop longue. c la première fois que je trouve JAVA bizarre (ou c moi ???).
 
En tout cas j'apprécie ton discours constructifs. je pense que "Rien ne sert de coder proprement pour tester qqch à l'origine"
Par contre ensuite, il est clair que c plutot indispensable.

Reply

Marsh Posté le 06-03-2004 à 01:59:34    

Une pile d'appel 17000 c'est déjà pas mal, hein [:kiki]

Reply

Marsh Posté le 06-03-2004 à 02:15:45    

benou a écrit :

Une pile d'appel 17000 c'est déjà pas mal, hein [:kiki]

ça dépend de la taille des frames, hein [:kiki]
 
 
bon et le monsieur il va arrêter de croire que c'est de la faute du matériel s'il a touché le fond de la pile !


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 06-03-2004 à 09:03:56    

Le programme est fait pour récupérer des zones d'une image. La fonction récursive fonctionnera ou non selon la taille de l'image.
J'aimerai savoir s'il faut que je traite en plusieurs fois l'image selon sa taille s'il existe une autre solution.
 
Ceci dit je n'ai pas encore trouvé un outil du type photoshop qui permet de faire un remplissage d'une zone non régulière en JAVA.

Reply

Marsh Posté le 06-03-2004 à 09:03:56   

Reply

Marsh Posté le 06-03-2004 à 09:14:57    

BifaceMcLeOD a écrit :


Ce qui confirme que la récursivité n'est pas faite pour des millers d'appels récursifs, seulement quelques dizaines ou quelques centaines.


 
De toute façon, il vaut mieux éviter au maximum d'écrire des fonctions récursives pour des raisons de performances ou sinon, de bien savoir ce que l'on fait. Souvent, cela revient à gaspiller sa cpu et d'autant plus que toute fonction récursive peut s'écrire avec un algo non-récursif.


Message édité par docmaboul le 06-03-2004 à 09:15:17
Reply

Marsh Posté le 06-03-2004 à 09:19:02    

DocMaboul a écrit :


 
De toute façon, il vaut mieux éviter au maximum d'écrire des fonctions récursives pour des raisons de performances ou sinon, de bien savoir ce que l'on fait. Souvent, cela revient à gaspiller sa cpu et d'autant plus que toute fonction récursive peut s'écrire avec un algo non-récursif.


 
merci de toutes vos remarques. Ca m'a fait pas mal avancé. Je vais ecrire une fonction avec des boucles imbriqués.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed