ChatGPT解决这个技术问题 Extra ChatGPT

How to force garbage collection in Java?

Is it possible to force garbage collection in Java, even if it is tricky to do? I know about System.gc(); and Runtime.gc(); but they only suggest to do GC. How can I force GC?

Perhaps it would be helpful to provide some background for why you need to force GC. Typically in a garbage collected language it is bad practice to explicitly call the collector.
A given JVM may provide several garbage collection methods, each with its own advantages and disadvantages, and frequently a given situation can be avoided simply by hinting the JVM at startup time. Please elaborate on scenario.
Here's a use case for forcing garbage collection: I have a server with a 30GB heap, of which ~12GB is typically used (~5M objects). Every 5 minutes, the server spends roughly one minute performing a complex task in which roughly 35M additional objects are used. A full GC is triggered a couple of times per hour, invariably during the complex task, and freezes the VM for 10 to 15 seconds. I would love to force the full GC to run at a time when the complex task is not running; it would then be juggling 5M live objects rather than 40M.
@JustinEthier There is one pretty obvious case where you may want to force the GC, which is unit testing any behaviour involving the java.lang.ref.Reference type hierarchy.

J
Jim Pivarski

Your best option is to call System.gc() which simply is a hint to the garbage collector that you want it to do a collection. There is no way to force and immediate collection though as the garbage collector is non-deterministic.


There should be. non-deterministic == trouble
A garbage collector may be non-deterministic and still offer a way to force an immediate collection. For example, usually the .NET collector is non-deterministic but a call to GC.Collect() forces it run. It's just that Java chooses not to expose this function.
In my experience, this method always invokes the garbage collector. It does so with enough regularity that my plots of memory use versus number of objects declared are always strictly linear (accounting for padding, etc.).
I was thinking that by allocating new objects and then not referencing them anymore, the garbage collector would automatically run
@Pacerier if you want deterministic behavior, you can nowadays use the Epsilon garbage collector. It deterministically never collects anything.
F
Flow

The jlibs library has a good utility class for garbage collection. You can force garbage collection using a nifty little trick with WeakReference objects.

RuntimeUtil.gc() from the jlibs:

   /**
    * This method guarantees that garbage collection is
    * done unlike <code>{@link System#gc()}</code>
    */
   public static void gc() {
     Object obj = new Object();
     WeakReference ref = new WeakReference<Object>(obj);
     obj = null;
     while(ref.get() != null) {
       System.gc();
     }
   }

This code is broken because a weak ref gets cleared as soon as its referent becomes weakly reachable, which is before it gets cleared from memory.
OP requested, and you claimed to provide, a solution to "force garbage collection". Running the GC subsystem is one thing, actually collecting garbage another. The code sample you provided has clearly the intention to guarantee garbage has been collected. Anyway, this being a very old question it's obviously not about OP's wishes, but utility to the general public. Nobody is interested in "forcing the GC subsystem to run" on its own, with no garbage being collected. In fact, people usually want a guarantee that all garbage has been collected.
So basically, that code does nothing better than System.gc(). A WeakReference getting cleared has nothing to do with memory reclamation. I personally have tested that code and found it to be useless. The ridiculously simple code System.gc(); System.gc(); had much better results.
You probably didn't compare it with the efficiency of System.gc(); System.gc();, but it sure would be interesting to know if it ever worked better than that. In fact, just printing how many times it called System.gc() would be enough. The chance to ever reach 2 is quite slim.
@MarkoTopolnik: 'Nobody is interested in "forcing the GC subsystem to run" on its own, with no garbage being collected'.... Actually I was interested in just this behavior today. I'm thankful this answer was present. My purpose was checking the rotational behavior of the GC log handling, and getting the format of the GC output. This little trick helped me to fill up the GC logs quickly.
p
prashant

The best (if not only) way to force a GC would be to write a custom JVM. I believe the Garbage collectors are pluggable so you could probably just pick one of the available implementations and tweak it.

Note: This is NOT an easy answer.


+1 for lulz. nothing makes frustrating debugging better than someone with a sense of humor. other than an actually useable answer, that is.
t
trashgod

Using the Java™ Virtual Machine Tool Interface (JVM TI), the function

jvmtiError ForceGarbageCollection(jvmtiEnv* env)

will "Force the VM to perform a garbage collection." The JVM TI is part of the JavaTM Platform Debugger Architecture (JPDA).


l
legramira

YES it is almost possible to forced you have to call to methods in the same order and at the same time this ones are:

System.gc ();
System.runFinalization ();

even if is just one object to clean the use of this two methods at the same time force the garbage collector to use the finalise() method of unreachable object freeing the memory assigned and doing what the finalize() method states.

HOWEVER it is a terrible practice to use the garbage collector because the use of it could introduce an over load to the software that may be even worst than on the memory, the garbage collector has his own thread which is not possible to control plus depending on the algorithm used by the gc could take more time and is consider very inefficient, you should check your software if it worst with the help of the gc because it is definitely broke, a good solution must not depend on the gc.

NOTE: just to keep on mind this will works only if in the finalize method is not a reassignment of the object, if this happens the object will keep alive an it will have a resurrection which is technically possible.


NO, even these two commands will NOT force a garbage collection. As already mentioned by others, gc() is only a hint to run a garbage collection. runFinalizers() only runs finalizers on objects "that have been found to be discarded". If the gc did not actually run, there may be no such objects...
also, System.runFinalization() isn't a guarantee that anything will run; it's possible that nothing will happen at all. It is a suggestion – from Javadoc: "Calling this method suggests that the Java Virtual Machine expend effort toward running the finalize methods of objects that have been found to be discarded but whose finalize methods have not yet been run"
P
Pete Kirkham

Under the documentation for OutOfMemoryError it declares that it will not be thrown unless the VM has failed to reclaim memory following a full garbage collection. So if you keep allocating memory until you get the error, you will have already forced a full garbage collection.

Presumably the question you really wanted to ask was "how can I reclaim the memory I think I should be reclaiming by garbage collection?"


N
Nathan

You can trigger a GC from the command line. This is useful for batch/crontab:

jdk1.7.0/bin/jcmd <pid> GC.run

See :

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html


Try adding some explanation, comments or description about references
According to the documentation, all this does is call System.gc(), and as it has been stated many times, System.gc() does not force garbage collection. docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/…
P
Pinkesh Sharma

To manually Request GC (not from System.gc()) :

Go To : bin folder in JDK eg.-C:\Program Files\Java\jdk1.6.0_31\bin Open jconsole.exe Connect to the desired local Process. Go To memory tab and click perform GC.


Oppsss misleading. Please mouse hover the "Perform GC" button. You can request JVM to perform GC but never force.
@PinkeshSharma, This doesn't force. It's a mere request which could probably be ignored entirely.
@Pacerier In an ideal world yes.. but if you do this you'll see that there is an increase in memory instantly...
C
Cameron McKenzie

How to Force Java GC

Okay, here are a few different ways to force Java GC.

Click JConsole's Perform GC button Use JMap's jmap -histo:live 7544 command where 7544 is the pid Call the Java Diagnostic Console's jcmd 7544 GC.run command Call System.gc(); in your code Call Runtime.getRuntime().gc(); in your code

https://i.stack.imgur.com/rJWUT.png

None of these work

Here's the dirty little secret. None of these are guaranteed to work. You really can't force Java GC.

The Java garbage collection algos are non-deterministic, and while all of these methods can motivate the JVM to do GC, you can't actually force it. If the JVM has too much going on and a stop-the-world operation is not possible, these commands will either error out, or they will run but GC won't actually happen.

if (input.equalsIgnoreCase("gc")) {
    System.gc();
    result = "Just some GC.";
}

if (input.equalsIgnoreCase("runtime")) {
    Runtime.getRuntime().gc();
    result = "Just some more GC.";
}

Fix the darn problem

If you've got a memory leak or object allocation problem, then fix it. Sitting around with your finger on Java Mission Control's Force Java GC button only kicks the can down the road. Profile your app with Java Flight Recorder, view the results in VisualVM or JMC, and fix the problem. Trying to force Java GC is a fools game.

https://i.stack.imgur.com/K3sbr.png


I'm surprised how many people ignore the one valid use case for System.gc(), or actually forcing a GC: Find out how much reachable memory is actually reachable. E.g. you want this during performance testing, and to determine a baseline value for -XmX - obviously you don't want or need it in production.
N
Nicholas Jordan

.gc is a candidate for elimination in future releases - a Sun Engineer once commented that maybe fewer than twenty people in the world actually know how to use .gc() - I did some work last night for a few hours on a central / critical data-structure using SecureRandom generated data, at somewhere just past 40,000 objects the vm would slow down as though it had run out of pointers. Clearly it was choking down on 16-bit pointer tables and exhibited classic "failing machinery" behavior.

I tried -Xms and so on, kept bit twiddling until it would run to about 57,xxx something. Then it would run gc going from say 57,127 to 57,128 after a gc() - at about the pace of code-bloat at camp Easy Money.

Your design needs fundamental re-work, probably a sliding window approach.


I have something like that, a lot of objects in memory I can't deallocate them. OutOfMemory exception is thrown, I want to Force GC to test if there is some Infinite Object creation process or these objects are the one used by my system.
Sounds like you are working on the same problem I am, pls explain: "Infinite Object creation" ... good research project, maybe you can post a question or something in a java area here ( I'm sort new here and to not know the "Finite Automa" of how the site works ) I tried yesterday and ended up doing file.dat as the compiler complained "too much code" on 40,000 base36 BigIntegers coded as a static final String[] I'm gonna stick my neck here and speculate that the entire JVM is limited on 16-bit pointers, I bet what we have to do is agressively null and read in from disk ...
Really, I don't get you. But to be clear about "Infinite Object Creation" I meant that there is some piece of code at my big system do creation of objects whom handles and alive in memory, I could not get this piece of code actually, just gesture!!
Nonsense! There is one obvious case where it should be used: testing code which uses weak references, so that we can make sure that behaviour is correct when weak references get cleared up.
While a Sun engineer may have told you this in 2009 or earlier, there is no sign that it is actually going to happen. It is now the end of 2020, and in the last 9 years / 9 Java releases, gc() has not been deprecated. Deprecation / removal would break too many existing applications for this to be seriously contemplated, IMO.
r
rai.skumar

JVM specification doesn't say anything specific about garbage collection. Due to this, vendors are free to implement GC in their way.

So this vagueness causes uncertainty in garbage collection behavior. You should check your JVM details to know about the garbage collection approaches/algorithms. Also there are options to customize behavior as well.


Good idea, I wonder if there's a particular GC where System.GC is guaranteed to "do something" :)
You are not and should not be guaranteed a GC sweep on its invocation, as there are layers of references, in fact a tree of references that the GC has to iterate through in order to detach each single node of the tree (reference to the object basically) and yet hold the tree valid. An immediate invocation doesn't sound practical; because, regardless of when it's invoked, GC has to clean the garbage up in a chained hierarchical fashion to not leave any objects in a null referenced state. But, cleaning up our code or rethinking around the logic is the best bet and by far the cleanest one.
B
Bob Kaufman

If you need to force garbage collection, perhaps you should consider how you're managing resources. Are you creating large objects that persist in memory? Are you creating large objects (e.g., graphics classes) that have a Disposable interface and not calling dispose() when done with it? Are you declaring something at a class level that you only need within a single method?


P
Paul Lammertsma

It would be better if you would describe the reason why you need garbage collection. If you are using SWT, you can dispose resources such as Image and Font to free memory. For instance:

Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();

There are also tools to determine undisposed resources.


what if there is not any dispose method?
Completely unrelated to the question! No, I'm not using SWT. I'm calling a JNI method that opens a .NET window through a Delphi native layer. I also have a FORTRAN computation core that receives data through a native C++ layer. What does that have to do with anything? Can I force a GC or not? No? :-(
Rebooting the machine is also a way of freeing up memory, although I doubt this answer helps you any more than finding a way of manually invoking garbage collection.
A
Aaron T Harris

Another options is to not create new objects.

Object pooling is away to reduce the need GC in Java.

Object pooling is generally not going to be faster than Object creation (esp for lightweight objects) but it is faster than Garbage Collection. If you created 10,000 objects and each object was 16 bytes. That's 160,000 bytes GC has to reclaim. On the other hand, if you don't need all 10,000 at the same time, you can create a pool to recycle/reuse the objects which eliminates the need to construct new objects and eliminates the need to GC old objects.

Something like this (untested). And if you want it to be thread safe you can swap out the LinkedList for a ConcurrentLinkedQueue.

public abstract class Pool<T> {
    private int mApproximateSize;
    private LinkedList<T> mPool = new LinkedList<>();

    public Pool(int approximateSize) {
        mApproximateSize = approximateSize;
    }

    public T attain() {
        T item = mPool.poll();
        if (item == null) {
            item = newInstance();
        }
        return item;
    }

    public void release(T item) {
        int approxSize = mPool.size(); // not guaranteed accurate
        if (approxSize < mApproximateSize) {
            recycle(item);
            mPool.add(item);
        } else if (approxSize > mApproximateSize) {
            decommission(mPool.poll());
        }
    }

    public abstract T newInstance();

    public abstract void recycle(T item);

    public void decommission(T item) { }

}

n
nabster

You can try using Runtime.getRuntime().gc() or use utility method System.gc() Note: These methods do not ensure GC. And their scope should be limited to JVM rather than programmatically handling it in your application.


As explained in the other answers, those methods do not force a (complete) garbage collection run.
R
Rahul Babu

We can trigger jmap -histo:live <pid> using the java runtime. This will force a full GC on heap to mark all the live objects.

public static void triggerFullGC() throws IOException, InterruptedException {
    String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
    Process process = Runtime.getRuntime().exec(
            String.format("jmap -histo:live %s", pid)
    );
    System.out.println("Process completed with exit code :" + process.waitFor());
}

I tried this, and the result is no better than System.gc()
M
Mike Nakis

I did some experimentation (see https://github.com/mikenakis/ForcingTheJvmToGarbageCollect) trying about a dozen different ways of performing a garbage collection, including ways described in this answer, and more, and I found that there is absolutely no frigging way to deterministically force the JVM to do a complete garbage collection. Even the best answers to this question are only partially successful in that the best they achieve is some garbage collection, but never a guaranteed full garbage collection.

My experimentation has showed that the following code snippet yields the best (least bad) results:

public static void ForceGarbageCollection()
{
    long freeMemory = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
    for( ; ; )
    {
        Runtime.getRuntime().gc();
        Runtime.getRuntime().runFinalization();
        long newFreeMemory = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
        if( newFreeMemory == freeMemory )
            break;
        freeMemory = newFreeMemory;
        sleep( 10 );
    }
}

Where the sleep() function is as follows:

private static void sleep( int milliseconds )
{
    try
    {
        Thread.sleep( milliseconds );
    }
    catch( InterruptedException e )
    {
        throw new RuntimeException( e );
    }
}

Unfortunately, that number 10 in that sleep( 10 ) is magic; it assumes that you are doing a moderate number of memory allocations per second, which incur a moderate amount of finalization. If you are going through objects faster, then 10 might be inadequate and you may need to wait longer. You could set it to 100 to be sure, but no matter what you set it to, there will always be a chance that it will not be enough.

That having been said, in a controlled environment where that 10 is enough, this approach has been observed to consistently eliminate all unreachable objects from memory, while no other approach mentioned in this Q&A does. The experiment code I linked to on github proves so.

In my opinion, the fact that the Java Virtual Machine provides no means of performing a forced-on-demand, unconditional, deterministic, absolutely thorough, stop-the-world garbage collection makes it BROKEN.

To put it in a different way, the creators of the JVM are so full of hubris as to think that they know better than us whether we want to do that or whether we should want to do that. Don't be so arrogant. If something works as if by magic, then some means of bypassing the magic must be provided.


V
Viktor Dahl

If you are running out of memory and getting an OutOfMemoryException you can try increasing the amount of heap space available to java by starting you program with java -Xms128m -Xmx512m instead of just java. This will give you an initial heap size of 128Mb and a maximum of 512Mb, which is far more than the standard 32Mb/128Mb.


The default memory settings are java -Xms512M -Xmx1024M
S
Sri9911

Really, I don't get you. But to be clear about "Infinite Object Creation" I meant that there is some piece of code at my big system do creation of objects whom handles and alive in memory, I could not get this piece of code actually, just gesture!!

This is correct, only gesture. You have pretty much the standard answers already given by several posters. Let's take this one by one:

I could not get this piece of code actually

Correct, there is no actual jvm - such is only a specification, a bunch of computer science describing a desired behaviour ... I recently dug into initializing Java objects from native code. To get what you want, the only way is to do what is called aggressive nulling. The mistakes if done wrong are so bad doing that we have to limit ourselves to the original scope of the question:

some piece of code at my big system do creation of objects

Most of the posters here will assume you are saying you are working to an interface, if such we would have to see if you are being handed the entire object or one item at a time.

If you no longer need an object, you can assign null to the object but if you get it wrong there is a null pointer exception generated. I bet you can achieve better work if you use NIO

Any time you or I or anyone else gets: "Please I need that horribly." it is almost universal precursor to near total destruction of what you are trying to work on .... write us a small sample code, sanitizing from it any actual code used and show us your question.

Do not get frustrated. Often what this resolves to is your dba is using a package bought somewhere and the original design is not tweaked for massive data structures.

That is very common.


Aggressive nulling used to be useful for the JVMs before Hotspot. Afterwards, we have been having a copying collector, where the number of dead objects does not matter.
M
Masarrat Siddiqui

FYI

The method call System.runFinalizersOnExit(true) guarantees that finalizer methods are called before Java shuts down. However, this method is inherently unsafe and has been deprecated. An alternative is to add “shutdown hooks” with the method Runtime.addShutdownHook.

Masarrat Siddiqui


The flaw with shutdown hooks is that they rarely actually work. Force terminating doesn't work, non-zero exit code doesn't work, and sometimes the (official) JVM simply doesn't run them as long as you need them to run.
A
Agnius Vasiliauskas

There is some indirect way for forcing garbage collector. You just need to fill heap with temporary objects until the point when garbage collector will execute. I've made class which forces garbage collector in this way:

class GarbageCollectorManager {

    private static boolean collectionWasForced;
    private static int refCounter = 0;

    public GarbageCollectorManager() {
        refCounter++;
    }

    @Override
    protected void finalize() {
        try {
            collectionWasForced = true;
            refCounter--;
            super.finalize();   
        } catch (Throwable ex) {
            Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public int forceGarbageCollection() {
        final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
        int iterationsUntilCollected = 0;
        collectionWasForced = false;

        if (refCounter < 2) 
            new GarbageCollectorManager();

        while (!collectionWasForced) {
            iterationsUntilCollected++;
            int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
            arr = null;
        }

        return iterationsUntilCollected;
    }

}

Usage:

GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();

I don't know how much this method is useful, because it fills heap constantly, but if you have mission critical application which MUST force GC - when this may be the Java portable way to force GC.


What is "final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;"?
Array size - how many temporary objects (int's) will be generated for GC to start working.
Yes, underscores in numeric literals are valid starting from Java SE 7. This is useful for example as thousands separator in integer as in this case.
You should never run such code in a production system. While this code runs in one thread any other thread may also get a OutOfMemoryException, completely reversion the intention of calling this in the first place....
@Steffen Heil: …and it may run forever, as garbage collection is not required to always collect all objects (and it’s easy to optimize away the array creation here). Further, garbage collection is not the same as finalization and finalizers are not required to run timely or ever at all. It would be an entirely plausible behavior to defer the finalization of that single pending object until that loop is over. Which leads to the loop never being over…
S
Saubhagya Ranjan Das

I would like to add some thing here. Please not that Java runs on Virtual Machine and not actual Machine. The virtual machine has its own way of communication with the machine. It may varry from system to system. Now When we call the GC we ask the Virtual Machine of Java to call the Garbage Collector.

Since the Garbage Collector is with Virtual Machine , we can not force it to do a cleanup there and then. Rather that we queue our request with the Garbage Collector. It depends on the Virtual Machine, after particular time (this may change from system to system, generally when the threshold memory allocated to the JVM is full) the actual machine will free up the space. :D


First sentence of the second paragraph is a non sequitur.
This answer is completely confusing the "Java Virtual Machine" (which is a bytecode interpreter) with a "Virtual Machine" (which is a way to emulate a processor on another processor). And no, the JVM isn't delegating GC to a lower-level machine, it has its own GC routines.
N
Nathan

On OracleJDK 10 with G1 GC, a single call to System.gc() will cause GC to clean up the Old Collection. I am not sure if GC runs immediately. However, GC will not clean up the Young Collection even if System.gc() is called many times in a loop. To get GC to clean up the Young Collection, you must allocate in a loop (e.g. new byte[1024]) without calling System.gc(). Calling System.gc() for some reason prevents GC from cleaning up the Young Collection.


A
Aliuk

If you are using JUnit and Spring, try adding this in every test class:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)