2017-04-20 4 views
0

Je travaille actuellement sur l'optimisation de mon application et j'ai remarqué qu'elle prend près de 1 Go de RAM. J'ai fait du profilage et trouvé le problème: J'allouais beaucoup de mémoire en créant des tableaux int contenant des données de pixels dans une classe de texture que j'avais créée. Mais cela m'embrouille, car lors de la création d'un nouveau tableau, l'ancien tableau n'est plus utilisé et il n'y a aucune référence.Java - les tableaux non référencés prennent encore de la mémoire

J'ai écrit un programme de test qui reproduit ce problème:

public class Main { 

    static class ArrayHolder { 
     int[] array; 

     void init() { 
      array = null; 
      array = new int[4000]; 
     } 
    } 

    public static void main(String[] args) { 
     ArrayHolder holder = new ArrayHolder(); 
     for (int i = 0; i < 1000000; i++) { 
      holder.init(); 
     } 
     System.out.println(holder.array.length); 
     try { 
      Thread.sleep(5000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Quand je lance ce code, le programme utilise jusqu'à 600 Mo de RAM. Je ne comprends pas pourquoi, car lorsque vous appelez la méthode init() dans ArrayHolder, le champ de tableau est défini sur le nouveau tableau et la référence à l'ancien est perdue. Cela ne veut-il pas dire qu'il ne prend plus de place? Je suis désolé si c'est une question noobish mais quelqu'un peut-il expliquer pourquoi c'est et ce que je fais mal ici?

+0

Votre ancien tableau ne sera lancé qu'à la discrétion de gc. Si gc s'exécute peu de temps après que vous ayez réalloué de la mémoire, l'espace sera récupéré autrement. – SMA

+0

de grands tableaux sont ajoutés à l'espace réservé et ce n'est que GC-ed par défaut quand il se remplit. par exemple. le sommeil ne déclenche pas de GC. En bref, créer beaucoup de grands tableaux comme celui-ci est mauvais idéal pour de nombreuses raisons. –

Répondre

1

est une référence à un tableau en Java. À cet égard, ils sont comme tout autre objet régulier dérivé de java.lang.Object. Une fois qu'il n'y a plus de références à un tableau, il est planifié pour la récupération de place, ce qui ne doit pas se faire immédiatement.

Il est peu probable que cette latence lors de la libération de la mémoire vous cause des problèmes: le garbage collector récupère les objets non désirés lorsqu'il en a besoin.

Notez que même si le garbage collector exécute, il n'y a toujours aucune garantie que le processus remettra la mémoire au système d'exploitation, ou le système d'exploitation récupérera la mémoire du processus.

+0

Merci d'avoir signalé cela. Comment allez-vous réduire l'utilisation de la mémoire pour cet exemple spécifique? Ou voulez-vous laisser cela au GC? Parce que 1 concert semble un peu trop pour une application simple. – RagingRabbit

+0

Je ferais simplement confiance au GC. 1GB est une simple pitance sur mes machines 192GB que j'ai ici, donc un pic de 1 Go n'est pas suffisant pour déclencher un GC sur ma boîte si les processeurs sont occupés. – Bathsheba

+0

J'ai réexécuté le programme avec JVisualVM et j'ai effectué une récupération de place avec, mais l'utilisation de la mémoire ne change pas. Le GC a-t-il décidé de ne pas percevoir ou est-ce un problème? – RagingRabbit

2

Le fait que votre objet ne possède pas de référence ne signifie pas qu'il ne prendra pas de mémoire. Le GC doit fonctionner et seulement alors il sera "retiré" de la mémoire. Vous pouvez avoir des objets sans références en mémoire qui occupent de l'espace. Vérifiez si GC a fonctionné, sinon appelez-le explicitement (pas une bonne idée pourtant). Aussi, je suggère de trouver si vous avez réellement des références fortes à votre objet (s).

Vous appelez explicitement appel GC en utilisant System.gc().

Vous pouvez ajouter des arguments JVM tels que '-XX: + PrintGCDetails' pour vérifier si GC a été exécuté.

+0

Comment vérifierait-il si le garbage collector a fonctionné, et comment l'appelle explicitement, et pourquoi ne devrait-il pas faire cela? – bleistift2

+0

@ bleistift2 - J'ai édité ma réponse pour ajouter ce dont vous aviez besoin. Pour savoir pourquoi appeler GC explicitement n'est pas une bonne idée, passez par http://stackoverflow.com/questions/66540/when-does-system-gc-do-anything – TheLostMind

+0

Notez que 'System.gc()' est consultatif. – Bathsheba