2010-08-02 5 views
4

Quand je lance le code suivant, il mange lentement ma mémoire et commence même en utilisant swap:Comment NSMutableData alloue-t-il de la mémoire?

long long length = 1024ull * 1024ull * 1024ull * 2ull; // 2 GB 

db = [NSMutableData dataWithLength:length]; 

char *array = [db mutableBytes]; 

for(long long i = 0; i < length - 1; i++) { 
     array[i] = i % 256; 
} 

Si je le lance sans pour le cycle sans mémoire est utilisée à tous:

long long length = 1024ull * 1024ull * 1024ull * 2ull; 
db = [NSMutableData dataWithLength:length]; 
char *array = [db mutableBytes]; 
/* for(long long i = 0; i < length - 1; i++) { 
     array[i] = i % 256; 
} */ 

Je peux seulement conclure que NSMutableData ne fait que "réserver" de la mémoire et quand on y accède, il l'"alloue" vraiment. Comment est-ce fait exactement?

Est-ce fait via le matériel (CPU)?

Existe-t-il un moyen pour NSMutableData d'intercepter les écritures de la mémoire dans sa mémoire "réservée" et de faire ensuite "l'allocation"?

Est-ce que cela signifie également qu'un appel à [NSMutableData dataWithLength:length] ne peut jamais échouer? Peut-il allouer n'importe quelle taille de mémoire en utilisant swap pour l'obtenir si nécessaire?

Si elle peut échouer, ma variable db sera-t-elle nulle?

Dans « NSMutableData Référence de la classe » de la pomme j'ai vu que des phrases vagues sur ces sujets.

Répondre

6

Ce n'est pas tellement un problème NSMutableData mais un problème noyau/OS. Si le processus demande un (gros) morceau de mémoire, le noyau dira normalement "c'est bon, c'est parti". Mais seulement en l'utilisant effectivement, il est vraiment ("physiquement") alloué. C'est correct car si votre programme commence avec une malloc de 2 Go (comme vous le faites ici), il serait impossible d'échanger instantanément d'autres programmes, alors qu'en pratique, vous n'utiliserez pas les 2 Go immédiatement.

Lors de l'accès à une page de mémoire qui n'est pas réellement présente dans la mémoire physique, le noyau recevra un signal de la CPU. Si la page devrait être là (parce qu'elle se trouve dans votre bloc de 2 Go), elle sera mise en place (probablement à partir du swap) et vous ne le remarquerez même pas. Si la page ne devrait pas être là (parce que l'adresse n'est pas allouée dans votre mémoire virtuelle) vous obtiendrez une erreur de segmentation (type d'erreur SIGSEGV ou EXC_BAD_ACCESS). L'un des sujets connexes est "overcommit (ment)", où le noyau promet plus de mémoire que ce qui est réellement disponible. Cela peut causer de sérieux problèmes si tous les processus commencent à utiliser leur mémoire promise. C'est dépendant du système d'exploitation.

Il y a beaucoup de pages sur Internet expliquant ce mieux et plus en détail; Je voulais juste faire une courte intro pour avoir les termes à mettre dans google.

modifier juste testé, linux facilement me promettre 4 To de mémoire, alors que - je vous assure - le stockage il n'y a même pas 1 To sur un total disque dans cette machine. Vous pouvez imaginer que cela, s'il n'est pas pris en charge, peut causer des maux de tête lors de la construction de systèmes critiques.

+1

Il est possible de modifier le comportement de surcharges Linux en définissant 'overcommit_memory' et' overcommit_ratio'. En particulier, si vous définissez 'overcommit_memory' sur 2, cela signifie que l'espace de swap ne sera validé que par overcommit_ratio% de la mémoire physique. –

+0

Voir aussi la documentation [overcommit-accounting] (http://www.mjmwired.net/kernel/Documentation/vm/overcommit-accounting). –

+0

La chose intéressante à propos de Linux est que 'mmap()' (que malloc fait derrière la surface) prend un drapeau 'MAP_NORESERVE', ce qui permet un comportement de sur-engagement. Cependant, si vous - comme malloc() - ne spécifiez pas ce drapeau, il y aura toujours un sur-engagement. – mvds

Questions connexes