Mémoire insuffisante lors de l'encodage du fichier en base64
En utilisant Base64 de Apache commons
public byte[] encode(File file) throws FileNotFoundException, IOException {
byte[] encoded;
try (FileInputStream fin = new FileInputStream(file)) {
byte fileContent[] = new byte[(int) file.length()];
fin.read(fileContent);
encoded = Base64.encodeBase64(fileContent);
}
return encoded;
}
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at org.apache.commons.codec.binary.BaseNCodec.encode(BaseNCodec.java:342)
at org.apache.commons.codec.binary.Base64.encodeBase64(Base64.java:657)
at org.apache.commons.codec.binary.Base64.encodeBase64(Base64.java:622)
at org.apache.commons.codec.binary.Base64.encodeBase64(Base64.java:604)
Je suis en train de faire petite application pour appareil mobile.
source d'informationauteur Ivan Ivanovich
Vous devez vous connecter pour publier un commentaire.
Vous ne pouvez pas charger tout le fichier en mémoire, comme ici:
Au lieu de charger le fichier de morceau par morceau et de l'encoder en pièces. Base64 est un codage simple, il suffit de charger 3 octets, et les encoder en même temps (cela va produire 4 octets après l'encodage). Pour des raisons de performances envisager de charger des multiples de 3 octets, par exemple, 3000 octets - devrait être très bien. Également envisager la mise en mémoire tampon d'entrée de fichier.
Un exemple:
Notez que vous ne pouvez pas ajouter simplement les résultats de
Base64.encodeBase64()
àencoded
bbyte tableau. En fait, il n'est pas de charger le fichier, mais l'encodage en Base64 causant le problème de mémoire. C'est compréhensible parce que Base64 version est plus grande (et vous avez déjà un fichier occupant beaucoup de mémoire).Envisager de changer votre méthode:
et de l'envoi des données codées en Base64 directement à la
base64OutputStream
plutôt que de le retourner.Mise à JOUR: Grâce à @StephenC j'ai développé beaucoup plus facile version:
Il utilise
Base64OutputStream
qui se traduit par l'entrée en Base64 à la volée etIOUtils
classe de Apache Commons IO.Remarque: vous devez fermer le
FileInputStream
etBase64OutputStream
explicitement à imprimer=
si nécessaire, mais de mise en mémoire tampon est gérée parIOUtils.copy()
.Soit le fichier est trop gros, ou votre tas est trop petit, ou alors vous avez une fuite de mémoire.
Si cela se produit uniquement avec de très gros fichiers, mettre quelque chose dans votre code pour vérifier la taille du fichier et de rejeter les fichiers qui sont excessivement gros.
Si ce qui se passe avec les petits fichiers, augmentation de la taille de segment de mémoire par l'utilisation de l'option-Xmx option de ligne de commande lors du lancement de la JVM. (Si c'est dans un conteneur web ou un autre cadre, consultez la documentation sur la façon de le faire.)
Si le fichier réapparaît, en particulier avec les petits fichiers, les chances sont que vous avez une fuite de mémoire.
L'autre point qui doit être faite est que votre approche implique la tenue de deux copies complètes du fichier en mémoire. Vous devriez être en mesure de réduire l'utilisation de la mémoire, si vous aurez généralement besoin d'une base de flux encoder en Base64 pour ce faire. (Cela dépend de la saveur de l'encodage base64 vous utilisez ...)
Cette page décrit une fonction de flux Base64 codeur /décodeur de la bibliothèque, et comprend lnks à quelques solutions de rechange.
Bien, ne pas le faire pour l'ensemble du dossier à la fois.
Base64 fonctionne sur 3 octets à la fois, de sorte que vous pouvez lire vos fichiers par lots de "multiple de 3" octets, encoder et répéter jusqu'à la fin du fichier:
Vous n'êtes pas lire le fichier en entier, juste le premier de quelques ko. Le
read
méthode renvoie le nombre d'octets ont été lus en réalité. Vous devriez appelerread
dans une boucle jusqu'à ce qu'il retourne-1
pour être sûr que vous avez tout lu.Le fichier est trop grand à la fois pour elle et son encodage base64 pour tenir en mémoire. Soit
augmenter la mémoire disponible pour la JVM avec le
-Xmx
de l'interrupteur, par exempleC'est le meilleur code pour télécharger l'image de taille plus
Bien, on dirait que votre fichier est trop volumineux pour garder les copies multiples nécessaire pour une mémoire de l'encodage Base64 dans le segment de mémoire en même temps. Étant donné que c'est pour un appareil mobile, ce n'est probablement pas possible d'augmenter le tas, donc, vous avez deux options:
InputStream
une petite partie du fichier à la fois, de coder et de les écrire sur unOutputStream
sans jamais garder le enitre fichier en mémoire.Dans le Manifeste en application reposant tag écrire la suite
android:largeHeap="true"
Il a travaillé pour moi