2017-04-20 3 views
0

Ich arbeite gerade daran, meine Anwendung zu optimieren, und mir ist aufgefallen, dass sie fast 1 GB Arbeitsspeicher beansprucht. Ich habe ein Profiling gemacht und das Problem gefunden: Ich habe viel Speicher reserviert, indem ich int-Arrays erstellt habe, die Pixeldaten in einer von mir erstellten Texturklasse enthalten. Aber das verwirrt mich, denn wenn man ein neues Array erstellt, wird das alte Array nicht mehr benutzt und es gibt keinen Bezug mehr.Java - nicht referenzierte Arrays nehmen immer noch Speicher auf

Ich habe ein Testprogramm geschrieben, das dieses Problem reproduziert:

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(); 
     } 
    } 
} 

Wenn ich diesen Code ausführen verwendet das Programm bis 600 Megabyte RAM. Ich verstehe nicht, warum, weil beim Aufrufen der Methode init() in ArrayHolder das Array-Feld auf das neue Array festgelegt wird und der Verweis auf den alten verloren geht. Würde das nicht bedeuten, dass es keinen Platz mehr einnimmt? Es tut mir leid, wenn das eine noobish Frage ist, aber kann jemand erklären, warum das ist und was ich hier falsch mache?

+0

Ihr altes Array würde nur im Ermessen von GC gestartet werden. Wenn GC bald nach der Neuzuweisung von Speicher ausgeführt wird, wird der Speicherplatz zurückgewonnen, andernfalls wird er nicht verwendet. – SMA

+0

große Arrays werden zum festen Speicherplatz hinzugefügt und dies wird standardmäßig nur GC-ed, wenn es voll ist. z.B. Schlafen löst keinen GC aus. Kurz gesagt, ist es aus so vielen Gründen schlecht, so viele große Arrays zu erstellen. –

Antwort

1

array ist eine Referenz zu einem Array in Java. In dieser Hinsicht sind sie wie jedes andere reguläre Objekt, das von java.lang.Object abgeleitet ist. Sobald keine Verweise auf ein Array mehr vorhanden sind, wird eine Garbage Collection geplant, die nicht sofort erfolgen muss.

Es ist unwahrscheinlich, dass diese Latenz bei der Speicherfreigabe zu Problemen führt: Der Garbage Collector wird bei Bedarf nicht referenzierte Objekte sammeln.

Beachten Sie, dass selbst wenn der Garbage Collector ausgeführt wird, gibt es immer noch keine Garantie, dass der Prozess den Speicher an das Betriebssystem zurückgibt, oder das Betriebssystem wird den Speicher zurück aus dem Prozess.

+0

Vielen Dank, dass Sie darauf hingewiesen haben. Wie würden Sie die Speicherbelegung für dieses spezielle Beispiel reduzieren? Oder würdest du das dem GC überlassen? Weil 1 Gig für eine einfache Anwendung ein bisschen zu viel erscheint. – RagingRabbit

+0

Ich würde einfach dem GC vertrauen. 1GB ist nur eine Kleinigkeit auf meinen 192GB Rechnern, die ich hier habe, also reicht ein 1GB Spike nicht aus, um einen GC auf meiner Box auszulösen, wenn die CPUs beschäftigt sind. – Bathsheba

+0

Ich habe das Programm erneut mit JVisualVM ausgeführt und ich habe damit eine Garbage Collection durchgeführt, aber die Speicherbelegung ändert sich nicht. Hat der GC gerade beschlossen, nicht zu sammeln, oder ist das ein Problem? – RagingRabbit

2

Nur weil Ihr Objekt keine Referenz hat, bedeutet das nicht, dass es keinen Speicher belegt. GC muss laufen und erst dann wird es aus dem Speicher "entfernt". Sie können Objekte ohne Referenzen im Speicher haben, die Platz beanspruchen. Überprüfen Sie, ob GC ausgeführt wurde, wenn nicht, rufen Sie sie explizit auf (keine gute Idee). Außerdem schlage ich vor, herauszufinden, ob Sie tatsächlich starke Referenzen auf Ihre Objekte haben.

Sie rufen explizit GC mit System.gc() aufrufen.

Sie können JVM-Argumente wie '-XX: + PrintGCDetails' hinzufügen, um zu prüfen, ob GC ausgeführt wurde.

+0

Wie würde er überprüfen, ob der Müllsammler gelaufen ist, und wie nennt man es Explikation, und warum sollte er das nicht tun? – bleistift2

+0

@ bleistift2 - Bearbeitete meine Antwort, um hinzuzufügen, was Sie brauchten. Warum GC explizit aufzurufen, ist keine gute Idee, gehen Sie durch http://stackoverflow.com/questions/66540/when-does-system-gc-do-anything – TheLostMind

+0

Beachten Sie, dass 'System.gc()' Advisory ist. – Bathsheba

Verwandte Themen