ChatGPT解决这个技术问题 Extra ChatGPT

How to free memory in Java?

Is there a way to free memory in Java, similar to C's free() function? Or is setting the object to null and relying on GC the only option?

Ok... let's get one thing straight. Just because you think something is bad practice and not something to encourage doing, does not make it worthy of a vote down. This is a clear and valid question, asking if there is a way to release memory in Java with out relying on garbage collection. While it may be discouraged and generally not useful or a good idea, you cannot know that there are not scenarios where it may be required with out knowing what Felix knows. Felix may not even be planning on using it. He may just want to know if it's possible. It, in no way, deserves a vote down.
For clarification, that's aimed at whomever voted this down - not previous comments necessarily.

D
Daniel Pryden

Java uses managed memory, so the only way you can allocate memory is by using the new operator, and the only way you can deallocate memory is by relying on the garbage collector.

This memory management whitepaper (PDF) may help explain what's going on.

You can also call System.gc() to suggest that the garbage collector run immediately. However, the Java Runtime makes the final decision, not your code.

According to the Java documentation,

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.


It does force the Garbage Collector to run. It does not force it to free memory though...
No Pablo, it does not force the GC to run.
I've been told by a very reliable person that all HotSpotVM's garbage collectors ignore System.gc() entirely.
On winXp java SE GC runs every System.gc() or almost every but API doc does not guarantee it.
@Pablo Santa Cruz What do you mean it does not free memory? I just tested it out on my program that seemed to have a leak and the ram usage seemed to stabilize? And Daniel just said it only suggests it then how come the percentage of ram used always stabilized each time I called the method. You people are confusing me.
A
Adamski

No one seems to have mentioned explicitly setting object references to null, which is a legitimate technique to "freeing" memory you may want to consider.

For example, say you'd declared a List<String> at the beginning of a method which grew in size to be very large, but was only required until half-way through the method. You could at this point set the List reference to null to allow the garbage collector to potentially reclaim this object before the method completes (and the reference falls out of scope anyway).

Note that I rarely use this technique in reality but it's worth considering when dealing with very large data structures.


If you really are doing alot of work on an object which is only used for part of a method I suggest either; your method is too compilicated, break the method into the before and after portions, or use a block for the first half of code (the later is more useful for test scripts)
The place where setting an object reference to null is important is when it's referenced from another long-lived object (or possibly from a static var). Eg, if you have a long-lived array of large objects, and you cease using one of those objects, you should set the array reference to null to make the object available for GC.
D
Dean J
System.gc(); 

Runs the garbage collector. 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.

Not recommended.

Edit: I wrote the original response in 2009. It's now 2015.

Garbage collectors have gotten steadily better in the ~20 years Java's been around. At this point, if you're manually calling the garbage collector, you may want to consider other approaches:

If you're forcing GC on a limited number of machines, it may be worth having a load balancer point away from the current machine, waiting for it to finish serving to connected clients, timeout after some period for hanging connections, and then just hard-restart the JVM. This is a terrible solution, but if you're looking at System.gc(), forced-restarts may be a possible stopgap.

Consider using a different garbage collector. For example, the (new in the last six years) G1 collector is a low-pause model; it uses more CPU overall, but does it's best to never force a hard-stop on execution. Since server CPUs now almost all have multiple cores, this is A Really Good Tradeoff to have available.

Look at your flags tuning memory use. Especially in newer versions of Java, if you don't have that many long-term running objects, consider bumping up the size of newgen in the heap. newgen (young) is where new objects are allocated. For a webserver, everything created for a request is put here, and if this space is too small, Java will spend extra time upgrading the objects to longer-lived memory, where they're more expensive to kill. (If newgen is slightly too small, you're going to pay for it.) For example, in G1: XX:G1NewSizePercent (defaults to 5; probably doesn't matter.) XX:G1MaxNewSizePercent (defaults to 60; probably raise this.)

XX:G1NewSizePercent (defaults to 5; probably doesn't matter.)

XX:G1MaxNewSizePercent (defaults to 60; probably raise this.)

Consider telling the garbage collector you're not okay with a longer pause. This will cause more-frequent GC runs, to allow the system to keep the rest of it's constraints. In G1: XX:MaxGCPauseMillis (defaults to 200.)

XX:MaxGCPauseMillis (defaults to 200.)


Commenting on my own post, this often doesn't do anything, and calling it repeatedly can cause the JVM to become unstable and whatnot. It may also run over your dog; approach with caution.
I would put heavy emphasis on the "suggests" part of "Calling the gc method suggests that the JVM expand effort"
@Jesper, Dean's answer states "suggests". In fact he posted the exact documentation from the method's javadocs...
@Software Monkey: Yes, I could have just edited it. But since Dean J was obviously active (posting only a few minutes ago), I figured it was a courtesy to ask him to do it. If he hadn't, I would have come back here and made the edit and deleted my comment.
It would also we worth saying WHY it is not recommended. If the JVM pays attention to the "suggestion" to run the GC, it will almost certainly make your app run slower, possibly by many orders of magnitude!
D
Dakkaron

*"I personally rely on nulling variables as a placeholder for future proper deletion. For example, I take the time to nullify all elements of an array before actually deleting (making null) the array itself."

This is unnecessary. The way the Java GC works is it finds objects that have no reference to them, so if I have an Object x with a reference (=variable) a that points to it, the GC won't delete it, because there is a reference to that object:

a -> x

If you null a than this happens:

a -> null
     x

So now x doesn't have a reference pointing to it and will be deleted. The same thing happens when you set a to reference to a different object than x.

So if you have an array arr that references to objects x, y and z and a variable a that references to the array it looks like that:

a -> arr -> x
         -> y
         -> z

If you null a than this happens:

a -> null
     arr -> x
         -> y
         -> z

So the GC finds arr as having no reference set to it and deletes it, which gives you this structure:

a -> null
     x
     y
     z

Now the GC finds x, y and z and deletes them aswell. Nulling each reference in the array won't make anything better, it will just use up CPU time and space in the code (that said, it won't hurt further than that. The GC will still be able to perform the way it should).


n
nsandersen

To extend upon the answer and comment by Yiannis Xanthopoulos and Hot Licks (sorry, I cannot comment yet!), you can set VM options like this example:

-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30

In my jdk 7 this will then release unused VM memory if more than 30% of the heap becomes free after GC when the VM is idle. You will probably need to tune these parameters.

While I didn't see it emphasized in the link below, note that some garbage collectors may not obey these parameters and by default java may pick one of these for you, should you happen to have more than one core (hence the UseG1GC argument above).

VM arguments

Update: For java 1.8.0_73 I have seen the JVM occasionally release small amounts with the default settings. Appears to only do it if ~70% of the heap is unused though.. don't know if it would be more aggressive releasing if the OS was low on physical memory.


Y
Yios

A valid reason for wanting to free memory from any programm (java or not ) is to make more memory available to other programms on operating system level. If my java application is using 250MB I may want to force it down to 1MB and make the 249MB available to other apps.


If you need to explicitly free a chunk of 249MB, in a Java program, memory management wouldn't be the first thing I'd want to work on.
But freeing storage inside your Java heap does not (in the general case) make the storage available to other apps.
j
jontro

I have done experimentation on this.

It's true that System.gc(); only suggests to run the Garbage Collector.

But calling System.gc(); after setting all references to null, will improve performance and memory occupation.


I think you can't say for sure that " calling System.gc(); after setting all references to null, will improve performance and memory occupation. ". Because there is huge computational complexity of System.gc(). And even after calling System.gc() & indeed collecting the garbage, the jvm may not give the memory back to OS or System. JVM may retain the memory for future reference. See this answer.
D
Darron

If you really want to allocate and free a block of memory you can do this with direct ByteBuffers. There is even a non-portable way to free the memory.

However, as has been suggested, just because you have to free memory in C, doesn't mean it a good idea to have to do this.

If you feel you really have a good use case for free(), please include it in the question so we can see what you are rtying to do, it is quite likely there is a better way.


S
Stefan Falk

Entirely from javacoffeebreak.com/faq/faq0012.html

A low priority thread takes care of garbage collection automatically for the user. During idle time, the thread may be called upon, and it can begin to free memory previously allocated to an object in Java. But don't worry - it won't delete your objects on you! When there are no references to an object, it becomes fair game for the garbage collector. Rather than calling some routine (like free in C++), you simply assign all references to the object to null, or assign a new class to the reference. Example : public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass } If your code is about to request a large amount of memory, you may want to request the garbage collector begin reclaiming space, rather than allowing it to do so as a low-priority thread. To do this, add the following to your code System.gc(); The garbage collector will attempt to reclaim free space, and your application can continue executing, with as much memory reclaimed as possible (memory fragmentation issues may apply on certain platforms).


O
Oskuro

In my case, since my Java code is meant to be ported to other languages in the near future (Mainly C++), I at least want to pay lip service to freeing memory properly so it helps the porting process later on.

I personally rely on nulling variables as a placeholder for future proper deletion. For example, I take the time to nullify all elements of an array before actually deleting (making null) the array itself.

But my case is very particular, and I know I'm taking performance hits when doing this.


Don't null each and every value. It's a waste of CPU time and manual work. Let the GC do the work it's supposed to do. Generally speaking, writing code in the style of the wrong language is a pretty bad idea. If you write Java, you should be writing Java, not C++. Otherwise you will end up with terrible, hard to maintain code, where major parts of the code don't actually do anything/don't make sense at all.
G
Gothri

* "For example, say you'd declared a List at the beginning of a method which grew in size to be very large, but was only required until half-way through the method. You could at this point set the List reference to null to allow the garbage collector to potentially reclaim this object before the method completes (and the reference falls out of scope anyway)." *

This is correct, but this solution may not be generalizable. While setting a List object reference to null -will- make memory available for garbage collection, this is only true for a List object of primitive types. If the List object instead contains reference types, setting the List object = null will not dereference -any- of the reference types contained -in- the list. In this case, setting the List object = null will orphan the contained reference types whose objects will not be available for garbage collection unless the garbage collection algorithm is smart enough to determine that the objects have been orphaned.


This is actually not true. The Java garbage collector is smart enough to handle that correctly. If you null the List (and the objects within the List don't have other references to them) the GC can reclaim all the objects within the List. It may choose to not do that at the present time, but it will reclaim them eventually. Same goes for cyclic references. Basically, the way the GC works is to esplicitly look for orphraned objects and then reclaim them. This is the whole job of a GC. The way you describe it would render a GC utterly useless.
B
Benjamin

Althrough java provides automatic garbage collection sometimes you will want to know how large the object is and how much of it is left .Free memory using programatically import java.lang; and Runtime r=Runtime.getRuntime(); to obtain values of memory using mem1=r.freeMemory(); to free memory call the r.gc(); method and the call freeMemory()


C
Community

Recommendation from JAVA is to assign to null

From https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html

Explicitly assigning a null value to variables that are no longer needed helps the garbage collector to identify the parts of memory that can be safely reclaimed. Although Java provides memory management, it does not prevent memory leaks or using excessive amounts of memory. An application may induce memory leaks by not releasing object references. Doing so prevents the Java garbage collector from reclaiming those objects, and results in increasing amounts of memory being used. Explicitly nullifying references to variables after their use allows the garbage collector to reclaim memory. One way to detect memory leaks is to employ profiling tools and take memory snapshots after each transaction. A leak-free application in steady state will show a steady active heap memory after garbage collections.