web-dev-qa-db-fra.com

Comment fonctionne l'allocation de mémoire d'une ArrayList?

Autant que je sache, lorsque nous créons une ArrayList:

ArrayList<String> list = new ArrayList<String>(SIZE);

La JVM lui réserve une partie de mémoire contiguë . Lorsque nous ajoutons de nouveaux éléments à notre liste, lorsque le nombre d'éléments atteint 75% de SIZE, il réserve une nouvelle partie de mémoire contiguë et copie tous les éléments.

Notre liste devient de plus en plus grande. Nous ajoutons de nouveaux objets et la liste doit être reconstruite à nouveau.

Qu'est-ce qui se passe maintenant?

La JVM recherche un segment de mémoire contigu, mais ne trouve pas assez d'espace.

Le ramasse-miettes peut essayer de supprimer certaines références inutilisées et de défragmenter la mémoire. Que se passe-t-il si la machine virtuelle Java n'est pas en mesure de réserver de l'espace pour une nouvelle instance de liste après ce processus?

En crée-t-il un nouveau en utilisant le segment maximal possible? Quelle Exception sera lancée?

J'ai lu cette question Java: Comment ArrayList gère la mémoire et l'une des réponses est:

La référence ne consomme pas beaucoup d'espace. mais de toute façon, une partie de l'espace est utilisée. Lorsque le tableau s'agrandit, cela pourrait poser un problème. Nous ne pouvons pas non plus oublier que nous avons d’autres choses qui utilisent l’espace mémoire.

29
ruhungry

Si la JVM n’est pas en mesure d’allouer la quantité de mémoire demandée, elle sera renvoyée.

OutOfMemoryError

C'est tout. En réalité, l’allocation de mémoire JVM n’a que deux résultats possibles:

  1. L'application reçoit la quantité de mémoire demandée.
  2. La machine virtuelle Java renvoie OutOfMemoryError.

Il n'y a pas d'options intermédiaires, comme une certaine quantité de mémoire est allouée.

Cela n'a rien à voir avec ArrayList , c'est un problème de machine virtuelle Java. Si vous demandez si ArrayList gère d'une manière ou d'une autre cette situation d'une manière particulière -, alors la réponse est "Non, ce n'est pas le cas". Il essaie simplement d'allouer la quantité de mémoire dont il a besoin et laisse JVM réfléchir au reste.

35
Denis Kulagin

En Java, les références à l'objet sont stockées dans la mémoire contiguë. Les objets réels peuvent rester de manière non contiguë. Ainsi, par exemple, votre tableau pourrait avoir 10 objets, JVM n'a besoin que de réserver de la mémoire pour les références d'objet, pas pour les objets. Donc, si chaque référence prend un octet (approximativement pas la valeur correcte), mais que chaque objet occupe un ko, et que vous avez un tableau de 10 éléments, JVm essaiera de réserver de la mémoire contiguë de seulement 1 * 10 B, soit 10 B. les objets peuvent résider dans 10 emplacements de mémoire différents totalisant 10 Ko. N'oubliez pas que les espaces mémoire contigus et non contigus sont destinés à la mémoire allouée au thread. 

Lorsqu'il a besoin de redimensionner le tableau, la machine virtuelle Java a tenté de trouver un tableau contigu de la nouvelle longueur. Donc, si vous souhaitez redimensionner le tableau de 10 à 20 éléments, il essaiera de réserver un espace contigu de 20 Ko (en utilisant l'exemple ci-dessus). S'il trouve cet espace, il fera une copie des références de l'ancien tableau vers le nouveau tableau. S'il ne trouve pas cet espace, il essaiera de faire un GC. S'il ne trouve toujours pas l'espace, il lève une exception OutofMemoryException.

Par conséquent, à tout moment lorsque vous redimensionnez le tableau, la machine virtuelle Java doit trouver une mémoire contiguë pour stocker les références du nouveau tableau de taille. Ainsi, si vous souhaitez étendre le tableau à une taille de 1000 éléments, et que chaque référence est un octet, le JVm essaiera de trouver une mémoire contiguë de 1000 * 1 Ko, ce qui correspond à 1 Mo. S'il trouve cette mémoire, il fera une copie des références et marquera l'ancienne mémoire contiguë pour GC, à chaque fois que GC s'exécutera la prochaine fois S'il ne parvient pas à trouver la mémoire, il essaiera de faire une GC, et s'il ne trouve toujours pas la mémoire contiguë, il lèvera une exception de mémoire insuffisante.

C'est le code dans ArrayList qui effectue le redimensionnement . http://grepcode.com/file/repository.grepcode.com/Java/root/jdk/openjdk/6-b14/Java/util/ArrayList .Java # ArrayList.ensureCapacity% 28int% 29

12
Biswajit_86

Cela lancera une OutOfMemoryError dès qu'il n'y aura plus assez d'espace dans le tas pour allouer le nouveau tableau.

Le ramassage des ordures sera toujours effectué avant que cette erreur ne soit générée. Cela compactera la mémoire et éliminera tous les tableaux de petites tailles qui ne sont plus utilisés. Mais il n’ya aucun moyen de contourner le fait que l’ancien tableau, le nouveau tableau et tous les objets contenus doivent tous être en mémoire en même temps pour que l’ancien contenu soit copié dans la nouvelle liste.

Ainsi, si votre limite de mémoire est de 10 Mo, et que la matrice prend 2 Mo et est dimensionnée jusqu'à 3 Mo, et que les chaînes occupent 6 Mo, le MOO sera lancé même si, après cette opération, vous ne disposez que de 3 6 = 9 Mo en mémoire. Une façon d'éviter cela, si vous souhaitez exécuter des limites de mémoire très importantes avec un grand tableau, consiste à redimensionner le tableau à sa taille maximale pour qu'il ne soit jamais redimensionné.

7
Russell Zahniser

Je suppose qu'il manquera de mémoire car il n'y aura pas d'espace à utiliser dans le cas où la machine virtuelle Java peut étendre la taille du tableau.

0
user3579257

La première chose que je veux corriger est que, lorsque nous ajoutons de nouveaux éléments à notre liste, lorsque le nombre d’éléments atteint 100% de SIZE, il conserve une nouvelle partie de mémoire contiguë et copie tous les éléments.

La nouvelle taille de ArrayList sera:

NewSize of ArrayList = (CurrentSize * 3/2) + 1

Mais aller de cette façon n'est jamais recommandé, si nous avons une idée de la quantité d'objets à stocker, nous pouvons utiliser le constructeur suivant de ArrayList: -

ArrayList ar = new ArrayList (int initialCapacity);

Si notre machine virtuelle Java ne peut pas spécifier suffisamment d’espace contigu sur le tas pour ArrayList, au moment de l’exécution, nous obtiendrons 

  • Erreur d'exécution: OutOfMemoryError
0
Abhinavece