Comment faire pour annuler le mappage d'un fichier à partir de la mémoire mappée à l'aide de FileChannel en java?
Je suis le mappage d'un fichier("sample.txt") de la mémoire à l'aide FileChannel.map()
et la fermeture de la chaîne à l'aide d' fc.close()
. Après cela, quand j'écris dans le fichier à l'aide de FileOutputStream, j'obtiens l'erreur suivante:
java.io.FileNotFoundException:
de l'échantillon.txt (L'opération demandée
ne peut pas être formé par sur un fichier avec une
mappée utilisateur ouverture de la section)
File f = new File("sample.txt");
RandomAccessFile raf = new RandomAccessFile(f,"rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
fc.close();
raf.close();
FileOutputStream fos = new FileOutputStream(f);
fos.write(str.getBytes());
fos.close();
Je suppose que cela peut être dû à un fichier d'être liés à la mémoire, même après que j'ai fermer la FileChannel
. Suis-je le droit?. Si oui, comment puis-je "détacher" le fichier de la mémoire?(Je ne trouve pas toutes les méthodes de l'API).
Merci.
Edit:
Dirait qu'il(l'ajout d'un unmap méthode) a été présenté comme RFE de soleil il y a quelque temps:
http://bugs.sun.com/view_bug.do?bug_id=4724038
- J'ai frappé le même problème douloureusement. Dans mon cas, j'ai essayé de mapper des milliers de fichiers dans la mémoire et il en résulte
OutOfMemoryError
, qui, je crois, est le résultat de l'épuisement des gestionnaires de fichiers. N'ayant aucun instrument pour annuler le mappage d'conduit à unpredictive comportement, même si la carte va essayer desleep(100)
&System.gc()
surOutOfMemoryError
− il reporte les convulsions.
Vous devez vous connecter pour publier un commentaire.
De la
MappedByteBuffer
javadoc:Essayez d'appeler
System.gc()
? Encore, ce n'est qu'une suggestion pour la VM.System.gc()
ou de reconsidérer votre mise en œuvre.Méthode statique suivante peut être utilisée:
Mais c'est dangereux de solution en raison des éléments suivants:
1) Mener à l'échec si quelqu'un l'utiliser MappedByteBuffer après unmap
2) Elle repose sur MappedByteBuffer détails de mise en œuvre
sun.misc.Cleaner
est présente dans tous les grands JDK saveurs (Oracle JDK, OpenJDK incl. Zoulou, IBM J9), à l'exception de SEP et Apache Harmony. Il est également susceptible d'être conservé dans le JDK 1.9 (voir openjdk.java.net/jeps/260)DirectBuffer
est "fermée" dans le gflogger.[WinXP,SunJDK1.6], j'avais mappé ByteBuffer prises de filechannel. Après lecture des posts enfin réussi à appeler un nettoyant grâce à la réflexion, sans soleil.* package importations. Plus de verrouillage de fichier est en attente.
modifier Ajouté JDK9+ code(Luc Hutchison).
Idées ont été prises à partir de ces postes.
* Comment faire pour annuler le mappage d'un fichier à partir de la mémoire mappée à l'aide de FileChannel en java?
* Des exemples de la forcer à libérer de la mémoire natif direct ByteBuffer a alloué, à l'aide du soleil.misc.Dangereux?
* https://github.com/elasticsearch/elasticsearch/blob/master/src/main/java/org/apache/lucene/store/bytebuffer/ByteBufferAllocator.java#L40
MappedByteBuffer
,ByteBuffer
etBuffer
n'ont pas la méthodecleaner
HotSpot 8 mise à Jour 172. Cependant, cette méthode est disponible dansDirectByteBuffer
.An illegal reflective access operation has occurred
avertissement sur stderr, ce qui est laid et ne peut pas être supprimée, et indique que cela pourrait briser dans l'avenir. Voir ma réponse distincte.JDK1.6, JDK1.7, JDK1.8, OpenJDK10
.soleil.misc.Nettoyeur javadoc dit:
Système En Cours D'Exécution.gc() est solution acceptable si vos tampons total taille est petite, mais si j'étais cartographie des gigaoctets de fichiers, j'essaierais de la mettre en œuvre comme ceci:
Mais! Assurez-vous que vous n'avez pas accès à cette mémoire tampon après le nettoyage ou vous allez vous retrouver avec:
Bonne chance!
Pour contourner ce bug en Java, j'ai eu à faire à la suivante, qui va travailler ok pour les petites et moyennes taille des fichiers:
J'ai trouvé des informations sur
unmap
, c'est une méthode deFileChannelImpl
et ne sont pas accessibles, de sorte que vous pouvez l'appeler en java réfléchir comme:MappedByteBuffer.unmap()
n'existe pas.MappedByteBuffer
, vous pouvez trouver deFileChannelImpl
. En fait, ce n'est pas vraiment un bon moyen deunmap buffer
La méthode couverts dans les autres réponses qui emploie
((DirectBuffer) byteBuffer).cleaner().clean()
ne fonctionne pas sur JDK 9+ (même en forme de reflet) sans afficher unAn illegal reflective access operation has occurred
avertissement. Cela permettra d'arrêter complètement de travailler à l'avenir la version de JDK. Heureusementsun.misc.Unsafe.invokeCleaner(ByteBuffer)
peut faire exactement la même appel pour vous, sans l'avertissement: (à partir de OpenJDK 11 source):Être un
sun.misc
classe, il sera retiré à un certain point. Il est intéressant de noter tous les appels mais celle-ci,sun.misc.Unsafe
sont estimés à partir directement àjdk.internal.misc.Unsafe
(je ne sais pas pourquoiinvokeCleaner(ByteBuffer)
n'est pas mandaté de la même manière que toutes les autres méthodes, c'était probablement une omission accidentelle).J'ai écrit le code suivant qui est en mesure de nettoyer/fermer/unmap DirectByteBuffer/MappedByteBuffer instances sur JDK 7/8, ainsi que JDK 9+, et cela ne donne pas le reflet d'avertissement:
Notez que vous devez ajouter le
requires jdk.unsupported
à votre module descripteur dans un modulaire d'exécution sur JDK 9+ (nécessaire pour l'utilisation deUnsafe
).Votre pot peut également avoir besoin d'
RuntimePermission("accessClassInPackage.sun.misc")
,RuntimePermission("accessClassInPackage.jdk.internal.misc")
, etReflectPermission("suppressAccessChecks")
.La mémoire mappée est utilisé jusqu'à ce qu'il soit libéré par le garbage collector.
De FileChannel docs
De MappedByteBuffer java doc
Donc, je suggère de s'assurer qu'il ne reste aucun des références à la mappé octets de la mémoire tampon, puis demander un garbage collection.
System.gc()
.OutOfMemoryError
. Les spécifications de garantie avant que l'exception est levée, le GC a été exécuté.C'est drôle de voir autant de recommandations à faire ce que l'Article 7 dans "Effective Java" spécifiquement dit de ne pas faire. Une résiliation de la méthode comme quoi @Whome fait et pas de références à la mémoire tampon est ce qui est nécessaire. GC ne peut pas être forcé.
Mais cela n'empêche pas les développeurs d'essayer. Une autre solution de contournement que j'ai trouvé est d'utiliser WeakReferences de http://jan.baresovi.cz/dr/en/java#memoryMap
Je voudrais essayer JNI:
Inclure des fichiers: windows.h pour Windows, sys/mmap.h pour les BSD, Linux, OSX.
Si le fichier mappé en mémoire tampon de l'objet peut être garanti pour être admissible pour la collecte des ordures, vous n'avez pas besoin de GC l'ensemble de la VM pour obtenir le tampon de la mémoire mappée pour être libéré. Vous pouvez appeler le Système.runFinalization() . Ce qui fera appel à la méthode finalize() sur le fichier mappé en mémoire tampon d'objet (si il n'y a pas de références dans votre application threads) qui permettra de libérer la mémoire mappée.
runFinalization
?La bonne solution ici est d'utiliser try-with-resources.
Cela permet la création de la voie & les autres ressources pour être portée à un bloc. Une fois le bloc de sortie, le Canal & les autres ressources sont partis & donc, ne peut pas être utilisé (comme rien n'a une référence à eux).
La projection en mémoire ne seront pas annulées jusqu'à la prochaine GC exécuter, mais au moins il n'y a pas tout en balançant ses références.