J'ai utilisé une variable contenant beaucoup de données, par exemple String data
. Je voulais utiliser une petite partie de cette chaîne de la manière suivante:
this.smallpart = data.substring(12,18);
Après quelques heures de débogage (avec un visualiseur de mémoire), j'ai découvert que le champ objets se smallpart
souvenait de toutes les données data
, bien qu'il ne contienne que la sous-chaîne.
Quand j'ai changé le code en:
this.smallpart = data.substring(12,18)+"";
..le problème a été résolu! Maintenant, mon application utilise très peu de mémoire maintenant!
Comment est-ce possible? Quelqu'un peut-il expliquer cela? Je pense que this.smallpart a continué à faire référence aux données, mais pourquoi?
MISE À JOUR: Comment puis-je effacer la grosse chaîne alors? Est-ce que data = new String (data.substring (0,100)) fera l'affaire?
la source
new String(String)
; voir stackoverflow.com/a/390854/8946 .Réponses:
Procédez comme suit:
crée un nouvel objet String (plus petit) et supprime la référence à la chaîne créée par substring (), permettant ainsi la récupération de place de celui-ci.
La chose importante à réaliser est que cela
substring()
donne une fenêtre sur une chaîne existante - ou plutôt, le tableau de caractères sous-jacent à la chaîne d'origine. Par conséquent, il consommera la même mémoire que la chaîne d'origine. Cela peut être avantageux dans certaines circonstances, mais problématique si vous souhaitez obtenir une sous-chaîne et supprimer la chaîne d'origine (comme vous l'avez découvert).Jetez un œil à la méthode substring () dans la source JDK String pour plus d'informations.
EDIT: Pour répondre à votre question supplémentaire, la construction d'une nouvelle chaîne à partir de la sous-chaîne réduira votre consommation de mémoire, à condition de supprimer toutes les références à la chaîne d'origine.
NOTE (janvier 2013). Le comportement ci-dessus a changé dans Java 7u6 . Le modèle de poids mouche n'est plus utilisé et
substring()
fonctionnera comme prévu.la source
String(String)
constructeur (c'est-à-dire le constructeur String prenant une chaîne en entrée) est utile:new String(data.substring(x, y))
fait effectivement la même chose que l'ajout""
, mais cela rend l'intention quelque peu plus claire.value
attribut de la chaîne d'origine. Je pense que c'est pourquoi la référence est conservée.Si vous regardez la source de
substring(int, int)
, vous verrez qu'elle renvoie:où
value
est l'originalchar[]
. Vous obtenez donc une nouvelle chaîne, mais avec le même sous-jacentchar[]
.Lorsque vous le faites,
data.substring() + ""
vous obtenez une nouvelle chaîne avec un nouveau sous-jacentchar[]
.En fait, votre cas d'utilisation est la seule situation où vous devez utiliser le
String(String)
constructeur:la source
new String(String)
; voir stackoverflow.com/a/390854/8946 .Lorsque vous utilisez
substring
, il ne crée pas réellement de nouvelle chaîne. Il fait toujours référence à votre chaîne d'origine, avec une contrainte de décalage et de taille.Donc, pour permettre à votre chaîne d'origine d'être collectée, vous devez créer une nouvelle chaîne (en utilisant
new String
ou ce que vous avez).la source
Parce que les chaînes Java sont constituées d'un tableau de caractères, d'un décalage de début et d'une longueur (et d'un hashCode mis en cache). Certaines opérations String, telles que la
substring()
création d'un nouvel objet String, partagent le tableau de caractères d'origine et ont simplement des champs de décalage et / ou de longueur différents. Cela fonctionne car le tableau de caractères d'une chaîne n'est jamais modifié une fois qu'il a été créé.Cela peut économiser de la mémoire lorsque de nombreuses sous-chaînes font référence à la même chaîne de base sans répliquer les parties qui se chevauchent. Comme vous l'avez remarqué, dans certaines situations, il peut empêcher les données inutiles d'être récupérées.
La façon "correcte" de résoudre ce problème est le
new String(String)
constructeur, c'est-à-direBTW, la meilleure solution globale serait d'éviter d'avoir de très grandes chaînes en premier lieu, et de traiter toute entrée en petits morceaux, aa quelques Ko à la fois.
la source
new String(String)
; voir stackoverflow.com/a/390854/8946 .En Java, les chaînes sont des objets immuables et une fois qu'une chaîne est créée, elle reste en mémoire jusqu'à ce qu'elle soit nettoyée par le ramasse-miettes (et ce nettoyage n'est pas quelque chose que vous pouvez tenir pour acquis).
Lorsque vous appelez la méthode de sous-chaîne, Java ne crée pas de nouvelle chaîne, mais stocke simplement une plage de caractères à l'intérieur de la chaîne d'origine.
Ainsi, lorsque vous avez créé une nouvelle chaîne avec ce code:
vous avez en fait créé une nouvelle chaîne lorsque vous avez concaténé le résultat avec la chaîne vide. C'est pourquoi.
la source
Tel que documenté par jwz en 1997 :
la source
Pour résumer, si vous créez beaucoup de sous-chaînes à partir d'un petit nombre de grandes chaînes, utilisez
Puisque vous n'utilisez que l'espace pour stocker les grosses chaînes, mais si vous extrayez une poignée de petites chaînes, à partir de pertes de grosses chaînes, alors
Gardera votre mémoire utilisée, car les grosses chaînes peuvent être récupérées lorsqu'elles ne sont plus nécessaires.
Ce que vous appelez
new String
est un rappel utile que vous obtenez vraiment une nouvelle chaîne, plutôt qu'une référence à l'original.la source
new String(String)
; voir stackoverflow.com/a/390854/8946 .Tout d'abord, l' appel
java.lang.String.substring
crée une nouvelle fenêtre sur l'originalString
avec l'utilisation du décalage et de la longueur au lieu de copier la partie importante du tableau sous-jacent.Si nous regardons de plus près la
substring
méthode, nous remarquerons un appel de constructeur de chaîneString(int, int, char[])
et le passerons ensemblechar[]
qui représente la chaîne . Cela signifie que la sous - chaîne occupera autant de mémoire que la chaîne d' origine .D'accord, mais pourquoi se
+ ""
traduit par une demande de moins de mémoire que sans elle ??Faire un
+
onstrings
est implémenté via l'StringBuilder.append
appel de méthode. Regarder l'implémentation de cette méthode enAbstractStringBuilder
classe nous dira qu'elle fait finalementarraycopy
avec la partie dont nous avons vraiment besoin (lasubstring
).Toute autre solution de contournement ??
la source
Ajouter "" à une chaîne économisera parfois de la mémoire.
Disons que j'ai une énorme chaîne contenant un livre entier, un million de caractères.
Ensuite, je crée 20 chaînes contenant les chapitres du livre comme sous-chaînes.
Ensuite, je crée 1000 chaînes contenant tous les paragraphes.
Ensuite, je crée 10 000 chaînes contenant toutes les phrases.
Ensuite, je crée 100 000 chaînes contenant tous les mots.
Je n'utilise toujours que 1 000 000 de caractères. Si vous ajoutez "" à chaque chapitre, paragraphe, phrase et mot, vous utilisez 5 000 000 de caractères.
Bien sûr, c'est complètement différent si vous n'extrayez qu'un seul mot de tout le livre, et que tout le livre peut être récupéré, mais ce n'est pas parce que ce mot contient une référence.
Et c'est encore différent si vous avez une chaîne d'un million de caractères et supprimez les tabulations et les espaces aux deux extrémités, faisant dire 10 appels pour créer une sous-chaîne. La façon dont Java fonctionne ou fonctionne évite de copier un million de caractères à chaque fois. Il y a un compromis, et c'est bien si vous savez quels sont les compromis.
la source