2017-09-25 2 views
1

En étudiant l'utilisation de la mémoire de mon application via Android Memory monitor de Studio Studio, je me suis rendu compte qu'il pouvait y avoir des fuites de mémoire principalement dues à l'augmentation progressive de la mémoire. Memory allocated taille qui est passée d'environ 30 Mo à 50 Mo, 70 Mo et atteignant près de 90 Mo.Comment éviter les fuites de mémoire liées au contexte dans android

Ces augmentations de l'allocation de mémoire sont causées par le passage des onglets (fragments) et Activities, en revenant aux activités initiales, etc.

La méthode la plus straight-forward (ou facile, je pourrais dire) de localiser Memory leaks pourrait être (comme this link describes the process) la vérification et l'analyse d'un fichier de mémoire .hprof après dumping a java memory heap dans Android Studio. Avec cette méthode, j'ai correctement identifié une fuite de mémoire comme je déclarais une variable static context (pas fier de lui).

Malheureusement, tout en vérifiant le bon onglet LeakedActivites je remarquai que CatalogActivity est toujours présent là, donc il y a encore une fuite de mémoire de contexte se produit en ce qui concerne mContext.

enter image description here

Cette fois, je suis incapable d'identifier la fuite de mémoire, comme je l'ai pas déclaré une variable mContext. (évidemment comme il a une profondeur de 6, il se réfère à un contexte global pour cette activité)

Comment puis-je identifier la fuite de mémoire qui se produit encore? Le comportement que j'ai décrit dans le premier paragraphe est-il normal? (augmentation progressive de l'allocation de mémoire à travers le temps)

de CatalogActivity:

public class CatalogActivity extends AppCompatActivity { 
    private ViewPager mViewPager; 
    private SectionsPageAdapter mSectionsPageAdapter; 
    private FirebaseAuth mFirebaseAuth; 
    private Context context; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     overridePendingTransition(R.anim.slidein, R.anim.slideout); 

     setContentView(R.layout.activity_catalog); 
     context = this; 

     mFirebaseAuth = FirebaseAuth.getInstance(); 
     mSectionsPageAdapter = new SectionsPageAdapter(getSupportFragmentManager()); 
     mViewPager = (ViewPager) findViewById(R.id.container); 
     setupViewPager(mViewPager); 

     TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); 
     tabLayout.setupWithViewPager(mViewPager); 

     int tabIcon1 = R.drawable.ic_collections_24dp; 
     int tabIcon2 = R.drawable.ic_book_black_24dp; 
     int tabIcon3 = R.drawable.ic_chat__24dp; 

     if (tabLayout.getTabAt(0) != null) { 
      tabLayout.getTabAt(0).setIcon(tabIcon1); 
     } 
     if (tabLayout.getTabAt(1) != null) { 
      tabLayout.getTabAt(1).setIcon(tabIcon2); 
      tabLayout.getTabAt(1).getIcon().setAlpha(128); 
     } 
     if (tabLayout.getTabAt(2) != null) { 
      tabLayout.getTabAt(2).setIcon(tabIcon3); 
      tabLayout.getTabAt(2).getIcon().setAlpha(128); 
     } 

     tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { 
      @Override 
      public void onTabSelected(TabLayout.Tab tab) { 
       int tabIconColor = ContextCompat.getColor(context, R.color.colorAccent); 
       if (tab.getIcon() != null) { 
        tab.getIcon().setColorFilter(tabIconColor, PorterDuff.Mode.SRC_IN); 
        tab.getIcon().setAlpha(255); 
       } 

      } 

      @Override 
      public void onTabUnselected(TabLayout.Tab tab) { 
       int tabIconColor = ContextCompat.getColor(context, R.color.grey); 
       if (tab.getIcon() != null) { 
        tab.getIcon().setColorFilter(tabIconColor, PorterDuff.Mode.SRC_IN); 
        tab.getIcon().setAlpha(128); 
       } 
      } 

      @Override 
      public void onTabReselected(TabLayout.Tab tab) { 

      } 
     }); 
     ViewServer.get(this).addWindow(this); 
    } 


    private void setupViewPager(ViewPager viewPager) { 
     SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager()); 
     adapter.addFragment(new CatalogFragment()); 
     adapter.addFragment(new MyBooksfragment()); 
     adapter.addFragment(new MyChatsFragment()); 
     viewPager.setAdapter(adapter); 
    } 


    public void switchContent(Fragment fragment) { 

     getSupportFragmentManager().beginTransaction() 
       .replace(R.id.container, fragment).commit(); 


    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.chat_menu, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.sign_out_menu) { 
      LoginManager.getInstance().logOut(); 
      mFirebaseAuth.signOut(); 
      loadLogInView(); 
     } 


     return super.onOptionsItemSelected(item); 
    } 

    private void loadLogInView() { 
     Intent intent = new Intent(this, LogInActivity.class); 
     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 
     startActivity(intent); 
    } 
} 

Note: L'augmentation progressive de l'allocation de mémoire se produit lorsque je déboguer l'application avec LG G6 (4 Go de RAM). Lors de l'utilisation d'un périphérique émulé Nexus 5, le comportement persiste mais est considérablement réduit (l'allocation de mémoire commence à 2 Mo et atteint un pic autour de 5 Mo).

+0

Je suis sûr qu'il y a beaucoup de bitmaps. c'est peut-être drôle - mais les bitmaps font une grande fuite de mémoire. – Peter

+0

s'il vous plaît ne nous obligent pas à aller à d'autres endroits pour regarder votre code –

+0

@Peter Mon application a environ 4 'GridViews' chaque entièrement rempli de bitmaps. Par conséquent, vous avez deviné correctement. Mais comment puis-je arrêter les fuites de mémoire provoquées par beaucoup de bitmaps dans 'GridView'? J'ai cherché beaucoup de messages et je n'ai pas trouvé une bonne solution. –

Répondre

0

J'ai eu un problème similaire, la mémoire allouée chaque fois sur le nouveau fragment créé n'a pas été rejetée sur détruire.

Le problème était dans une liste de drawables ArrayList<Drawable>, définissant à null tous les éléments du tableau dans onDestroyView le problème a été résolu.

Je pense que vous devriez essayer de définir des variables nulles avec des références aux bitmaps dans votre GridView.

J'espère que cela aidera ...

+0

Les fuites de mémoire peuvent être causées par la grande quantité de références de bitmaps qui ne sont pas supprimées par le GC. Pourtant j'utilise un 'GridView' qui n'est pas un' ArrayList '. (Les bitmaps sont chargés à partir de la base de données dans l'adaptateur). Est-il possible de couper les fuites en utilisant 'GridView'? –

+0

Est-ce que vous fermez le curseur ou tout ce que vous utilisez pour obtenir les bitmaps de la base de données? –

+0

Je reçois seulement l'URI pour ces bitmaps (de DB) et je les charge avec la bibliothèque de 'Picasso 'ainsi donc la fuite ne devrait pas être de là. Je pense toujours que je devrais en quelque sorte gérer le 'GridView' peuplé dans le' OnDestroy' (en mettant en quelque sorte tous les bitmaps de ImageView) à null). Mais je cherche une façon plus élégante de le faire. –