user179172
user179172

Reputation:

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?

Upvotes: 277

Views: 449743

Answers (26)

Vlasec
Vlasec

Reputation: 5546

Note that WeakReference has optional parameter for its constructor of type ReferenceQueue.

When its content is being garbage-collected, the reference puts itself into the queue. This can be used (among others) as a form of detection of GC being run, e.g. by this simple snippet I made:

public static void awaitGc() throws Exception {
    var queue = new ReferenceQueue<>();
    var ref = new WeakReference<>(new Object(), queue);
    System.gc();
    while(queue.poll() == null)
        Thread.sleep(10);
}

I have a map-like cache with weak references to its values, and this snipped helped me test its correctness after garbage collection. To my surprise, the sleep is more useful than it seems.

My uneducated assumption would be that the "stop the world" action, necessary for GC to be performed, is seen as less invasive when all threads sleep.

Without sleep, the method (even with calling System.gc() in a cycle and hinting very hard to the system that GC would be feasible) took anything from hundreds of millis to two seconds. Introducing sleep seems to have shortened the required time to about 25 millis, provided that there aren't some other threads that experience heavy traffic.

I am not certain of the completeness of garbage collection, but in my test case it works well.

Note: I'm open to feedback whether this snippet works on other JREs and OSes. On my dev machine, I'm currently using Ubuntu and OpenJDK 11.

Upvotes: 0

legramira
legramira

Reputation: 598

YES it is almost possible to force. You have to call two methods in the same order and at the same time. These ones are:

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

even if there is just one object to clean, the use of this two methods at the same time forces the garbage collector to call the finalize() method of unreachable objects 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 worse than the memory, the garbage collector has its own thread which is not possible to control plus depending on the algorithm used by the gc could take more time and is considered very inefficient, you should check your software if it is worse with the help of the gc because it is definitely broken, a good solution must not depend on the gc.

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

Upvotes: 26

Andrew Hare
Andrew Hare

Reputation: 351476

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 an immediate collection though as the garbage collector is non-deterministic.

Upvotes: 203

I wanted to force gc, because my code was frozen for a long time when it happened. The aim is to smooth the charge, by regularly cause gc. The solutions listed doesnt forced anything in my environment.

So:

  • I request the memory for temporary variable,
  • simply, by increments,
  • and monitor the memory and stop the operation as soon as gc is triggered.

It works easily but you have to tune.

Runtime rt = Runtime.getRuntime();
double usedMB = (rt.totalMemory() - rt.freeMemory()) / 1024 / 1024;

if (usedMB > 1000) // only when necessary
{
byte[][] for_nothing = new byte[10][];

for (int k = 0; k < 10 ; k ++)
    for_nothing[k] = new byte[100_000_000];
}

System.gc();
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization(); 

Upvotes: 0

Mike Nakis
Mike Nakis

Reputation: 61969

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.

Upvotes: 0

Rahul Babu
Rahul Babu

Reputation: 790

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

Upvotes: 1

Cameron McKenzie
Cameron McKenzie

Reputation: 3880

How to Force Java GC

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

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

enter image description here

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.

enter image description here

Upvotes: 15

nabster
nabster

Reputation: 1665

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.

Upvotes: 1

shams
shams

Reputation: 3508

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

Upvotes: 66

Nicholas Jordan
Nicholas Jordan

Reputation: 656

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:

  1. 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:

  1. 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.

Upvotes: -1

Nathan
Nathan

Reputation: 8920

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.

Upvotes: -2

guest
guest

Reputation: 277

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

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

See :

Upvotes: 25

Aliuk
Aliuk

Reputation: 1359

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

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)

Upvotes: -4

Mainguy
Mainguy

Reputation: 1659

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.

Upvotes: 58

Aaron T Harris
Aaron T Harris

Reputation: 3095

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) { }

}

Upvotes: 1

Saubhagya Ranjan Das
Saubhagya Ranjan Das

Reputation: 287

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

Upvotes: -2

Agnius Vasiliauskas
Agnius Vasiliauskas

Reputation: 11267

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.

Upvotes: -2

rai.skumar
rai.skumar

Reputation: 10667

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.

Upvotes: 7

Pinkesh Sharma
Pinkesh Sharma

Reputation: 2456

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

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

Upvotes: 17

trashgod
trashgod

Reputation: 205775

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).

Upvotes: 48

Masarrat Siddiqui
Masarrat Siddiqui

Reputation: 27

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

Upvotes: -2

Viktor Dahl
Viktor Dahl

Reputation: 1990

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.

Upvotes: -1

Nicholas Jordan
Nicholas Jordan

Reputation: 656

.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.

Upvotes: 12

Pete Kirkham
Pete Kirkham

Reputation: 49311

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?"

Upvotes: 23

Bob Kaufman
Bob Kaufman

Reputation: 12815

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?

Upvotes: 4

Paul Lammertsma
Paul Lammertsma

Reputation: 38252

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.

Upvotes: 1

Related Questions