1
votes

Java String Pool Quelle est la meilleure façon de stocker des milliers de chaînes. GC fonctionne sur un pool de chaînes

Cas d'utilisation:
Récupérez l'URL de tous les clips de s3 sous forme de liste de chaînes. Soumettez ensuite le clip de la liste au résumé.

   public static void main(String[] args) {
    List<String> randomStringList = getListOfRandomeStrings();

}


static List<String> getListOfRandomeStrings() {
    List<String> randomStringList = new ArrayList<>();
    // Add 2k strings to randomStringList
    return randomStringList;
}

static void iterateList(List<String> randomStrings) {

    // Iterate and print strings
}

Questions

1) Quand les chaînes du pool de chaînes seront-elles récupérées?
2) Existe-t-il un moyen de nettoyer les cordes?
3) Est-ce que l'utilisation de la référence faible aide?

A référencé ce lien, mais pas toujours clair Quand une chaîne sera-t-elle récupérée en java


3 commentaires

D'après ce que je comprends, ils seront mis dans une file d'attente pour le ramasse-miettes lorsqu'ils auront fini d'être utilisés (c'est-à-dire hors de portée). Je pense qu'il existe une commande qui forcera le ramassage des ordures, mais je laisserais simplement java décider quand le faire


@DustinNieffenegger Il n'y a pas de commande qui force le GC à devenir actif. Vous demandez gentiment à la JVM de "s'il vous plaît envisager de faire une exécution GC maintenant", ce que la JVM fait à propos de votre demande appartient à la JVM.


Je me suis penché davantage et je suis d'accord! C'est simplement une suggestion, pas une exigence. Même avec un appel à system.runFinalization () (qui est également juste une suggestion), il n'y a aucune garantie que le garbage collection sera effectué immédiatement. C'est pourquoi, encore une fois, je dis laissez simplement java décider quand le faire!


3 Réponses :


4
votes

1) Il n'y a aucun moyen de prédire le nettoyage de la mémoire dans JVM.

2) Il n'y a aucun moyen de forcer le nettoyage de la mémoire dans JVM.

3) Les stocker comme références faibles aidera à les effacer (éventuellement) plus tôt:

Un objet faiblement référencé est effacé par le garbage collector lorsqu'il est faiblement accessible.

Une accessibilité faible signifie qu'un objet n'a ni références fortes ni souples pointant vers lui. L'objet ne peut être atteint qu'en traversant une référence faible.

Premièrement, le Garbage Collector efface une référence faible, de sorte que le référent n'est plus accessible. Ensuite, la référence est placée dans une file d'attente de référence d'où nous pouvons l'obtenir.

Vous pouvez appeler System.gc () pour suggérer la JVM de collecter les déchets, mais il n'y a aucune garantie solide.

Si vous manquez de mémoire, en théorie, les références faibles et souples sont les premiers candidats à la suppression.

2000 de chaînes d'URL avegare occuperont environ plusieurs mégaoctets de mémoire (qu'est-ce qu'un "meh" même pour une machine normale).

Je vous suggère donc plutôt de le faire de manière naturelle - mettez-les hors de portée lorsque vous n'en avez pas besoin et ne vous inquiétez pas tant que vous n'avez pas vraiment besoin de vous soucier de l'optimisation de la mémoire.


5 commentaires

Ainsi est le tien. C'est toujours agréable de voir comment plusieurs réponses se rejoignent et construisent plus que la somme des parties ;-)


Ok, permettez-moi de poser la question d'une manière différente si nous créons une référence faible pour la liste de chaînes. Les chaînes du pool de chaînes seront-elles supprimées lors de la suppression de l'objet de liste. Selon ma compréhension non. Je voulais donc savoir quand les pools de chaînes seront ramassés.


Je suis confronté à une erreur OutOfMemory. La seule chose que nous faisons est de charger le tri des chaînes de 1k et de le transmettre à un autre composant.


@ user3024119 Ensuite, soit votre JVM est démarré avec pas assez de mémoire, soit, plus probablement, votre code est bogué et crée une vraie fuite de mémoire quelque part. Donc, la vraie réponse ici est: activez la journalisation GC pour votre JVM, et commencez à étudier ce qui se passe vraiment .


En complément du commentaire de @ GhostCat, une référence faible n'est pas magique. Si les objets ne sont pas récupérés, il existe au moins une référence qui l'empêche. La création d'une référence faible supplémentaire ne change rien à cela. L'essentiel est la référence déjà existante. Vous devez l'identifier et si cela n'est pas nécessaire, supprimez-le simplement. Mais si la référence est nécessaire, il n'y a aucun moyen d'ajouter plus de mémoire.



3
votes

Hmm, pourquoi voulez-vous que les choses soient collectées immédiatement ?!

La JVM est responsable de la gestion de sa mémoire. Il effectuera un ramassage des ordures lorsqu'il le jugera nécessaire.

Bien sûr: plus tôt vos références disparaîtront de la vie, plus rapidement les objets deviendront éligibles au ramasse-miettes, et bien sûr, des références faibles peuvent vous aider.

Mais la vraie réponse: ne vous lancez pas dans l'optimisation prématurée. Si vous pensez qu'il y a un problème, effectuez une analyse comparative appropriée. Vous faites actuellement des hypothèses sur un problème hypothétique et une solution hypothétique. C'est rarement un bon point de départ!

Et veuillez noter: Les chaînes sont créées dans un pool de chaînes. Cela n'est vrai que pour les chaînes littérales du code source. Vos chaînes sont toutes créées via new String () à la fin. Consultez ici pour en savoir plus.


5 commentaires

Sagement, comme toujours :)


pourquoi voulez-vous que les choses soient collectées immédiatement? Nous traitons 100 tâches par seconde. Nous continuons donc à créer 1 000 chaînes par travail. Nous allons bientôt tomber sur Out of memory.


Les chaînes sont créées dans le pool de chaînes. Je voulais donc savoir quand il sera ramassé.


@ user3024119 Il me semble que vous essayez de résoudre le vrai problème avec les seules hypothèses théoriques. Commencez le profilage et trouvez des nombres exacts. Vous chassez des fantômes maintenant.


@ user3024119 d'abord, comme déjà dit, les chaînes ne sont pas "créées dans le pool", mais même si votre code les a placées explicitement dans le pool, cela n'a eu aucun impact sur le garbage collection. Ils sont toujours collectés lorsqu'ils ne sont pas utilisés. En règle générale, n'essayez pas de résoudre un problème sauf si vous avez un problème.



0
votes

Une façon de faire est de stocker les chaînes dans un ByteBuffer en utilisant la mémoire directe, puis d'utiliser sun.misc.Cleaner pour l'effacer dès que vous avez terminé. À partir de java 9, le nettoyeur est passé à java.lang.ref ( détaillé ici) . Il existe des cas d'utilisation où vous devez gérer un grand nombre de chaînes pendant un court instant et ne pas stresser le gc.
J'ai utilisé le Cleaner quand il était dans sun.misc, au lieu de publier mon propre code, je fournirai cet exemple assez détaillé .


3 commentaires

@GhostCat Avec Java9, le nettoyeur est passé à java.lang.ref mais sinon vous avez raison. Il est plus probable qu'il y ait une fuite de ressources dans le code. Il existe cependant des cas d'utilisation où il est intéressant de pouvoir effacer des chaînes (ou l'équivalent) une fois que vous en avez fini avec elles et j'ai voulu y éclairer quelques options.


Si vous modifiez votre réponse en conséquence, en ajoutant peut-être un lien vers le javadoc Java9, mon vote positif sera avec vous ;-)


J'ai lu la question plusieurs fois et je ne sais toujours pas quel problème vous voulez résoudre. Le PO a posé quelques questions très génériques.