web-dev-qa-db-fra.com

Comment changer la taille de la pile en utilisant ulimit ou par processus sur Mac OS X pour un programme C ou Ruby?

Il semble que la méthode recommandée pour définir la taille de la pile pour un programme C ou Ruby programme (qui utilise la pile C)) consiste à utiliser ulimit dans le shell Bash. Mais

$ ulimit -s
8192

$ ulimit -s 16384
-bash: ulimit: stack size: cannot modify limit: Operation not permitted

et Sudo n'aide pas non plus. Existe-t-il un moyen de le définir sur 16 Mo, 32 Mo ou 64 Mo? Je pensais qu'il devrait y avoir un moyen de le définir par invocation de programme au lieu de définir également un paramètre à l'échelle du système?

Maintenant 8192 signifie probablement 8 Mo, ce qui est assez petit, si on le compare à la quantité qu'un processus peut utiliser, parfois jusqu'à 2 Go de RAM.

(note mise à jour:ulimit -a peut afficher ses valeurs actuelles).

(mise à jour 2: il semble que ulimit -s <value> est par Shell, et que si vous le définissez la première fois, cela fonctionne généralement. Le problème est que lorsque vous le définissez la deuxième fois, il peut retourner une erreur)

17

Apparemment, il existe une limite stricte sur la taille de la pile pour mac os x, tirée de http://lists.Apple.com/archives/scitech/2004/Oct/msg00124.html étant donné que c'est assez ancien , et je ne sais plus si c'est toujours vrai, mais pour le définir, appelez simplement ulimit -s hard, son 65532. ou environ 65 mégaoctets.

J'ai fait quelques tests sur le léopard des neiges, 10.6.8, et cela semble vrai.

$ ulimit -a
...
stack size              (kbytes, -s) 8192
...
$ ulimit -s 65533
-bash: ulimit: stack size: cannot modify limit: Operation not permitted
$ ulimit -s 65532
$

J'ai également trouvé cela http://linuxtoosx.blogspot.com/2010/10/stack-overflow-increasing-stack-limit.html même si je ne l'ai pas testé, donc je ne peux pas vraiment dire beaucoup à ce sujet.

Lorsque les applications consomment des quantités de mémoire généralement extraites du tas, la pile est généralement réservée aux variables automatiques locales qui existent pendant une durée relativement courte équivalente à la durée de vie de l'appel de fonction, le tas est l'endroit où la plupart des données persistantes vivent .

voici un petit tutoriel:

#include <stdlib.h>

#define NUMBER_OF_BYTES 10000000 // about 10 megs
void test()
{
   char stack_data[NUMBER_OF_BYTES];          // allocating on the stack.
   char *heap_data = malloc(NUMBER_OF_BYTES); // pointer (heap_data) lives on the stack, the actual data lives on the heap.
}

int main()
{   
    test(); 
    // at this point stack_data[NUMBER_OF_BYTES] and *heap_data have being removed, but malloc(NUMBER_OF_BYTES) persists.
    // depending on the calling convention either main or test are responssible for resetting the stack.
    // on most compilers including gcc, the caller (main) is responssible.

    return 0;
}

$ ulimit -a
...
stack size              (kbytes, -s) 8192
...
$ gcc m.c
$ ./a.out
Segmentation fault
$ ulimit -s hard
$ ./a.out
$

ulimit n'est que temporaire, vous devrez le mettre à jour à chaque fois, ou mettre à jour le script bash correspondant pour le définir automatiquement.

Une fois ulimit réglé, il ne peut être abaissé que jamais augmenté.

11
Samy Vilar

À mon avis, la réponse acceptée n'est pas totalement correcte et conduit à une mauvaise compréhension, plus précisément la dernière affirmation n'est pas vraie.

ne fois ulimit réglé, il ne peut être abaissé que jamais élevé.

Il existe en effet soft (affichable avec ulimit -s ou ulimit -Ss) et dur (affichable avec ulimit -Hs) limites. Mais tout en fixant la limite par ulimit -s affectera les valeurs soft et hard.

Une fois la limite dure définie, elle ne peut être abaissée que jamais, mais la limite souple peut être abaissée ou augmentée à condition que la valeur reste inférieure à la limite dure.

Cela fonctionnera:

# base values
$ ulimit -s
100
$ ulimit -Hs
100
$ ulimit -Ss
100
# lower soft limit only
$ ulimit -Ss 50
$ ulimit -s
50
$ ulimit -Hs
100
$ ulimit -Ss
50
# raise soft limit only
$ ulimit -Ss 100
$ ulimit -s
100
$ ulimit -Hs
100
$ ulimit -Ss
100
# lower soft and hard limit
$ ulimit -s 50
$ ulimit -s
50
$ ulimit -Hs
50
$ ulimit -Ss
50
# then impossible to raise soft limit due to hard limit
$ ulimit -s 100
-bash: ulimit: stack size: cannot modify limit: Operation not permitted
$ ulimit -Ss 100
-bash: ulimit: stack size: cannot modify limit: Invalid argument
2
MisterFruits

La taille de pile par défaut du système varie d'une version différente du noyau à l'autre. Mon 10.7 est 16384, de sorte que ulimit -s 16384 est accepté par mon Mac. Tu peux essayer sysctl kern.stack_size et affiche la taille de la pile en lecture seule. le mien est le 16384.
Vous pouvez voir cet article technique, http://developer.Apple.com/library/mac/#qa/qa1419/_index.html , pour voir comment modifier la pile par défaut taille pour le programme C. Pour Ruby, car il s'agit d'un langage de script, vous devez agrandir sa taille de pile lors de la liaison Ruby. Sauf pour les appels de fonction ou la récursivité très profonds, ou pour avoir un très grand tableau et des objets alloués dans la pile, votre programme ne devrait pas avoir un espace de pile énorme. Au lieu de cela, l'utilisation de tas ou d'allocation dynamique peut utiliser jusqu'à 2 Go de RAM comme vous le souhaitez.

1
jclin

J'ai trouvé qu'en utilisant /bin/zsh au lieu de /bin/sh a fait disparaître cette erreur.

Pour moi, l'erreur se produisait dans un script Shell qui appelait ulimit -s unlimited. Lorsque le script a été interprété par /bin/sh (c.-à-d. avait #!/bin/sh comme première ligne du fichier de script), il a bloqué avec cette erreur. En revanche, lorsque vous le modifiez pour utiliser zsh, tout semble bien fonctionner. zsh était assez intelligent pour interpréter unlimited comme "donnez-moi la plus grande limite que le système d'exploitation me laisse", et tout fonctionnait comme vous le souhaitiez.

0
D.W.