Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (120)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Question about System.gc();  (Read 1577 times)
0 Members and 1 Guest are viewing this topic.
Offline tyeeeee1
« Posted 2013-04-07 17:29:49 »

I've been trying to figure out how to play .mid files without using a ton of RAM for the past two days and I've finally found some code that worked well. After a few tests and some profiling I noticed that the used RAM just kept going up and up so I decided that System.gc(); might fix this problem, it did.

My question is... Is it ok for me to be using System.gc(); like this? I've read that most people don't know how to properly use it and that there shouldn't be any need to use it so I'm not too sure if I should be using it. Using System.gc(); did take the used RAM from 60-130+mb before being reduced to a constant 35-40mb before being reduced.

Method that uses System.gc();
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
public void meta(MetaMessage event) {
    if (event.getType() == END_OF_TRACK_MESSAGE)
    {
      if(sequencer != null && sequencer.isOpen() && loop)
      {
        sequencer.setMicrosecondPosition(0);
        sequencer.start();
        System.gc();
        System.out.println("Test1");
      }
      else
      {
          sequencer.stop();
          sequencer.close();
          System.out.println("Test");
      }
    }
  }


Whole class.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
package Core;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

public class MidiPlayer implements MetaEventListener {

  // Midi meta event
  public static final int END_OF_TRACK_MESSAGE = 47;

  private Sequencer sequencer;

  private boolean loop;

  private boolean paused;

  /**
   * Creates a new MidiPlayer object.
   */

  public MidiPlayer() {
    try {
      sequencer = MidiSystem.getSequencer();
      sequencer.open();
      sequencer.addMetaEventListener(this);
    } catch (MidiUnavailableException ex) {
      sequencer = null;
    }
  }

  /**
   * Loads a sequence from the file system. Returns null if an error occurs.
   */

  public Sequence getSequence(String filename) {
    try {
      return getSequence(new FileInputStream(filename));
    } catch (IOException ex) {
      ex.printStackTrace();
      return null;
    }
  }

  /**
   * Loads a sequence from an input stream. Returns null if an error occurs.
   */

  public Sequence getSequence(InputStream is) {
    try {
      if (!is.markSupported()) {
        is = new BufferedInputStream(is);
      }
      Sequence s = MidiSystem.getSequence(is);
      is.close();
      return s;
    } catch (InvalidMidiDataException | IOException ex) {
      ex.printStackTrace();
      return null;
    }
  }

  /**
   * Plays a sequence, optionally looping. This method returns immediately.
   * The sequence is not played if it is invalid.
   */

  public void play(Sequence sequence, boolean loop) {
    if (sequencer != null && sequence != null && sequencer.isOpen()) {
      try {
        sequencer.setSequence(sequence);
        sequencer.start();
        this.loop = loop;
      } catch (InvalidMidiDataException ex) {
        ex.printStackTrace();
      }
    }
  }

  /**
   * This method is called by the sound system when a meta event occurs. In
   * this case, when the end-of-track meta event is received, the sequence is
   * restarted if looping is on.
   */

  @Override
  public void meta(MetaMessage event) {
    if (event.getType() == END_OF_TRACK_MESSAGE)
    {
      if(sequencer != null && sequencer.isOpen() && loop)
      {
        sequencer.setMicrosecondPosition(0);
        sequencer.start();
        System.gc();
        System.out.println("Test1");
      }
      else
      {
          sequencer.stop();
          sequencer.close();
          System.out.println("Test");
      }
    }
  }

  /**
   * Stops the sequencer and resets its position to 0.
   */

  public void stop() {
    if (sequencer != null && sequencer.isOpen()) {
      sequencer.stop();
      sequencer.setMicrosecondPosition(0);
    }
  }

  /**
   * Closes the sequencer.
   */

  public void close() {
    if(sequencer != null && sequencer.isOpen()) {
      sequencer.close();
    }
  }

  /**
   * Gets the sequencer.
   */

  public Sequencer getSequencer() {
    return sequencer;
  }

  /**
   * Sets the paused state. Music may not immediately pause.
   */

  public void setPaused(boolean paused) {
    if(this.paused != paused && sequencer != null && sequencer.isOpen()) {
      this.paused = paused;
      if (paused) {
        sequencer.stop();
      } else {
        sequencer.start();
      }
    }
  }

  /**
   * Returns the paused state.
   */

  public boolean isPaused() {
    return paused;
  }
}
Offline matheus23

JGO Kernel


Medals: 109
Projects: 3


You think about my Avatar right now!


« Reply #1 - Posted 2013-04-07 17:42:38 »

Hm. I wouldn't suggest using System.gc(). It's horribly slow, since it simply forces to delete all garbage, which exists. This is bad since usually the GC puts all the garbage into several buckets (yeah, the GC is sorting the garbage ^^). So the garbage, which exists longer dies slowly. The objects which are allocated all the time again and again are garbaged frequently.

You can think of the JVM's GC techneque like this: Take up as much memory as I can get. Do the least possible garbagecollections.
Don't worry about your program taking 100mb+ memory. If the JVM hasn't got that much disk space available, it simply doesn't use so much.
I've noticed my programs to use up to 200 times as much memory then after GC'ing (not even talking about heap ^^).

The only thing you can do about it is probably reduce the heap space you give the JVM using '-Xmx' and '-Xms' vm parameters, though I wouldn't suggest that either.

TL;DR: Don't worry. And System.gc() is slow. Trade Memory for less CPU time.

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline actual

JGO Coder


Medals: 23



« Reply #2 - Posted 2013-04-07 18:06:16 »

System.gc() does not guarantee that a garbage collection will take place at that moment. It simply "suggests" it to the JVM, so the GC may or may not actually happen. From the api:

"Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects."

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline nsigma
« Reply #3 - Posted 2013-04-07 18:13:41 »

Dang!  You didn't buy that RAM for it to actually be used by anything did you?!  Tongue

Seriously, unused RAM is a sign of an unoptimized system.  Let the JVM and the OS manage the RAM for you - it will do a damn sight better job of it.

Take @matheus23's suggestion for command line options to control heap size if you really feel you must.  Just don't use System.gc() - as well as the arguments already put, a full GC is likely to play havoc with MIDI / audio timing too. 

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline Cero
« Reply #4 - Posted 2013-04-07 22:45:08 »

You should read this thread I made once: So I use System.gc() manually, is it really that bad ?

The basic things were mentioned:
- dont use it as a general rule
- and its just a suggesting, dont a command per se

also the garbage will be collected automatically and if needed anyway.

That being said, I do use it in out big game. Whenever a new map is loaded, I call System.gc(). Because if you have map change / loading screen, that is really the best time to this, so I say "yeah go ahead and clean out the garbage now, if its convenient" aka System.gc() - because generally I would prefer it to happen during the map change and not during the game which can potentially cause a short lag... which I'm 99% sure wont happen, but you know *shrug*

so thats the only place to use this

if you feel that a certain place would be really nice for a gc() but its not necessary, and this line of code isnt reached too often - go ahead.

Be also aware that the use is "officially" discouraged, meaning "findBugs" and of course freaking "PMD" which are code analysis tools will warn about its usage.
I think findbugs says "should only be used in debug builds"

Offline sproingie

JGO Kernel


Medals: 202



« Reply #5 - Posted 2013-04-08 14:57:01 »

Where you know you're discarding a lot of previous state and there's a natural pause in your app like a loading screen, then and only then it does make some sense to call System.gc.  As for System.gc() being just a suggestion, it's a strong suggestion.  Think of it more like a signal: unless it has really good reason to ignore it, such as a gc signal already pending, or not having promoted anything since the last gc, you can be pretty sure it's going to run -- just not synchronously, that is, when System.gc() returns, nothing has happened yet.

Calling it too often defeats the purpose of the GC though.  If you're finding gc pauses are taking too much time when they do happen, you're better off tuning things like CMS initiating occupancy fraction.
Offline matheus23

JGO Kernel


Medals: 109
Projects: 3


You think about my Avatar right now!


« Reply #6 - Posted 2013-04-08 16:23:58 »

just not synchronously, that is, when System.gc() returns, nothing has happened yet.

Well, it looks like it is synchronoulsy, which is why I think it's generally a bad Idea to use it. From the docs:

When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

(Blah blah, I'm sure this was more than only 10% text per quote, blah blah)

See my:
    My development Blog:     | Or look at my RPG | Or simply my coding
http://matheusdev.tumblr.comRuins of Revenge  |      On Github
Offline 65K
« Reply #7 - Posted 2013-04-08 16:57:27 »

If you want to keep garbage piles low and prefer short but frequent garbage collections, use the G1:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=[n]

There might also be this parameter needed, depending on the JDK version:
-XX:+UnlockExperimentalVMOptions

Offline nsigma
« Reply #8 - Posted 2013-04-08 17:04:12 »

If you want to keep garbage piles low and prefer short but frequent garbage collections, use the G1:
-XX:+UseG1GC

Still not managed to get that to perform any better (or even as good as) -Xincgc for me.  Must test again sometime though.

The max pause setting may work with other garbage collectors too.

Praxis LIVE - open-source intermedia toolkit and live interactive visual editor
Digital Prisoners - interactive spaces and projections
Offline xsvenson
« Reply #9 - Posted 2013-04-13 22:53:07 »

First of all, trust gc.
Second of all, if the gc explicitly isn't the problem, trust gc.

When indeed the gc gets to be a bottleneck (like say 60 second full collection and then another one), then there are a few different gc's to try out. Everyone having some or lots of parameters to tweak it.
But gc tweaking should be done on already ready and released application, it is highly dependent on the application itself, it's client side modification and can vary significantly between different versions of java.
It's a science in itself.

Basically trust gc and write Your code Smiley

Edit: typos, oh my

“The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet.” - Michael A. Jackson
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 407
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2013-04-14 10:46:03 »

Aside... something rarely noticed but often the cause of serious strange pauses is use of Soft/Weak references and finalizers, which are orders of magnitude slower than plain GC.

Cas Smiley

Offline sproingie

JGO Kernel


Medals: 202



« Reply #11 - Posted 2013-04-14 23:35:45 »

using finalize(), Soft References, or Weak References causes the referent object to always miss one gc cycle, and only be collected by slower the slower gc methods. 

PhantomReferences don't have this problem, but you do have to do extra work to maintain the association to the referent since the phantomref by design won't.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Longarmx (52 views)
2014-10-17 03:59:02

Norakomi (44 views)
2014-10-16 15:22:06

Norakomi (34 views)
2014-10-16 15:20:20

lcass (38 views)
2014-10-15 16:18:58

TehJavaDev (68 views)
2014-10-14 00:39:48

TehJavaDev (68 views)
2014-10-14 00:35:47

TehJavaDev (60 views)
2014-10-14 00:32:37

BurntPizza (73 views)
2014-10-11 23:24:42

BurntPizza (45 views)
2014-10-11 23:10:45

BurntPizza (87 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!