Bien qu'un tampon mappé puisse utiliser moins de mémoire physique à un instant donné, il requiert toujours un espace d'adressage (logique) disponible égal à la taille totale (logique) du tampon. Pour aggraver les choses, il se peut (probablement) que cet espace d'adresse soit contigu. Pour une raison quelconque, cet ancien ordinateur semble incapable de fournir suffisamment d'espace d'adressage logique supplémentaire. Deux explications possibles sont (1) un espace d'adressage logique limité + une mémoire tampon importante et (2) une limitation interne que le système d'exploitation impose à la quantité de mémoire pouvant être mappée en tant que fichier pour les E/S. En ce qui concerne la première possibilité, considérons le fait que dans un système de mémoire virtuelle, chaque processus s'exécute dans son propre espace d'adressage logique (et a donc accès à l'adresse complète de 2^32 octets). Donc, si - au moment où vous essayez d'instancier le MappedByteBuffer
- la taille actuelle du processus JVM plus la taille totale (logique) du MappedByteBuffer
est supérieure à 2^32 octets (~ 4 gigaoctets), alors vous rencontreriez un (ou toute autre erreur/exception que cette classe a choisi de lancer à sa place, par exemple IOException: Map failed
). En ce qui concerne la deuxième possibilité, la façon la plus simple d'évaluer ceci est de profiler votre programme/la JVM lorsque vous essayez d'instancier le MappedByteBuffer
. Si la mémoire allouée du processus JVM + le totalTargetSize
requis sont bien en deçà du plafond de 2^32 octets, mais que vous obtenez toujours une erreur "map failed", il est probable qu'une limite interne de l'OS sur la taille des fichiers mappés en mémoire est la cause-racine.
Alors qu'est-ce que cela signifie dans la mesure du possible?
- N'utilisez pas cet ancien PC.(préférable, mais probablement pas réalisable)
- Assurez-vous que tout le reste de votre JVM a une empreinte mémoire aussi faible que possible pour la durée de vie du
MappedByteBuffer
. (plausible, mais peut-être non pertinent et définitivement irréalisable)
- Brisez ce fichier en plus petits morceaux, puis travaillez sur un seul bloc à la fois. (peut dépendre de la nature du fichier)
- Utilisez un tampon différent/plus petit. ... et vient de supporter la baisse des performances. (ce qui est la solution la plus réaliste, même si elle est le plus frustrant)
En outre, ce qui est exactement le totalTargetSize
pour votre cas de problème?
EDIT:
Après avoir fait quelques recherches, il semble clair que la IOException est due à running out of address space in a 32-bit environment. Cela peut se produire même lorsque le fichier lui-même est inférieur à 2^32 octets, soit en raison de l'espace d'adressage contigu insuffisante, ou en raison d'autres besoins d'espace d'adressage suffisamment importants dans la JVM simultanément combiné avec demande (see comments). Pour être clair, un IOE peut toujours être lancé plutôt qu'un MOO even if the original cause is ENOMEM. En outre, il semble y avoir des problèmes avec les environnements 32 bits plus anciens [insérer Microsoft OS ici] en particulier (example, example).
Ainsi, il semble que vous ayez trois choix principaux.
- Utilisez complètement "the 64-bit JRE or...another operating system".
- Utilisez un tampon plus petit d'un type différent et opérez sur le fichier en morceaux. (et prenez la performance en raison de ne pas utiliser un tampon mappé)
- Continuez à utiliser le
MappedFileBuffer
pour des raisons de performances, mais opérez également sur le fichier en plus petits morceaux afin de contourner les limitations d'espace d'adressage.
La raison pour laquelle je mets à l'aide MappedFileBuffer
en petits morceaux comme troisième est à cause des problèmes bien établis et non résolus dans l'annulation du mappage d'un MappedFileBuffer
(example), ce qui est quelque chose que vous auriez nécessairement à faire entre le traitement de chaque morceau dans afin d'éviter de toucher le plafond de 32 bits en raison de l'empreinte de l'espace d'adressage combiné des mappages accumulés. (NOTE: ceci s'applique uniquement si c'est le plafond de l'espace d'adressage 32 bits et pas certaines restrictions internes du système d'exploitation qui posent problème ... si ce dernier, ignorez ce paragraphe) Vous pouvez essayer this strategy (supprimer toutes les références puis exécuter le GC), mais vous seriez essentiellement à la merci de la façon dont le GC et votre système d'exploitation sous-jacent interagissent en ce qui concerne les fichiers mappés en mémoire. Et d'autres solutions de contournement potentielles qui tentent de manipuler plus ou moins directement le fichier mappé en mémoire sous-jacent (example) sont extrêmement dangereux et spécifiquement condamnés par Oracle (see last paragraph). Enfin, compte tenu du fait que le comportement GC n'est pas fiable de toute façon, et que la documentation officielle indique explicitement que "many of the details of memory-mapped files [are] unspecified", je voudrais pas recommander d'utiliser comme ceci sans tenir compte de toute solution de contournement que vous pourriez lire.Donc, sauf si vous êtes prêt à prendre le risque, je suggérerais soit de suivre le conseil explicite d'Oracle (point 1), soit de traiter le fichier comme une séquence de plus petits morceaux utilisant un type de tampon différent (point 2).
Il a échoué car il ne peut pas allouer autant d'espace _address_ sur 32 bits. Il ne s'agit pas d'insuffisance physique de RAM. –
mais la taille du fichier est seulement 200mb, cela devrait être bon shoudnt –
Vous ne pouvez pas être sûr, il a besoin d'un bloc contigu de cette taille. –