Explain this System.gc() behavior - java

In the book Thinking in Java, the author provides a technique to force garbage collection of an object. I wrote a similar program to test this out (I'm on Open JDK 7):
//forcing the garbage collector to call the finalize method
class PrintMessage
{
private String message;
public PrintMessage (String m)
{
this.message = m;
}
public String getMessage()
{
return this.message;
}
protected void finalize()
{
if(this.message == ":P")
{
System.out.println("Error. Message is: " + this.message);
}
}
}
public class ForcingFinalize
{
public static void main(String[] args)
{
System.out.println((new PrintMessage(":P")).getMessage());
System.gc();
}
}
The trick, as it appear to me, is to create a new object reference and not assign it: new PrintMessage();.
Here's what's mystifying me. When I compile and run this program, I get the following expected output:
:P
Error. Message is: :P
However, if I modify the first line of my main() function like this:
(new PrintMessage(":P")).getMessage();
I do not see any output. Why is it that System.gc() is calling the garbage collector only when I send the output to standard output? Does that mean JVM creates the object only when it sees some "real" use for it?

The object will be created, the bytecode compiler will not optimize that away. What happens in the second case is that your program exits before the output is actually flushed to your terminal (or maybe even before the finalizer is run, you never know when the GC and finalization actually happens). If you add a Thread.sleep() after the System.gc() call you will see the output.

Related

Why does nulling a variable during a method call make the value passed to the method null aswell?

I'm pretty confused about some java behavior, especially because my previous understanding of java was that it was strictly pass-by-value.
If I pass an object to a method, then null that object in the calling thread, I would expect the object would still exist and be able to be operated on in the method, but this is not the case.
Here is some sample code:
public class methodTest {
boolean bool;
boolean secondBool;
Test list;
public static void main(String[] args) {
new methodTest().run();
}
public void run() {
list = new Test();
new Thread(() -> {
func(list);
}).start();
list = null;
bool = true;
while (!secondBool) {
// block
}
System.gc();
}
public void func(Test big) {
while (!bool) {
// block
}
System.out.println(big);
secondBool = true;
}
class Test {
#Override
protected void finalize() throws Throwable {
System.out.println("I'm getting cleaned up!");
}
#Override
public String toString() {
return "Test!";
}
}
}
This code prints
null
I'm getting cleaned up!
when I would expect it to print:
Test!
I'm getting cleaned up!
I included the garbage collection call at the end and the finalize method in the class to ensure that the gc wasn't getting to the variable list before the function could print it, but the same effect occurs without it.
What is the explanation for this behavior?
EDIT:
Another example of this would be if you changed the list = null line in the run method to list = new Test(), then slightly modified the toString to count the number of Test instances. The program would print "Test2" instead of "Test1", because the value of the parameter in func was overridden in the calling thread, even though in my understanding of java's pass-by-value system, this should not happen.
It prints null because there is a race condition and the new thread loses most of the time.
The timing is like this:
the main thread (the one running methodTest.run()) creates a new Thread object and starts the new thread (meaning it creates a new linux/windows thread and notifies it that it can start running)
as the very next step it sets the instance variable list to null
in parallel to the step 2 above the second thread starts running and eventually reaches the lambda () -> { func(list); }
only when the second thread executes func(list); will it read the instance variable list
What is passed as parameter big into func therefore entirely depends on
how much time the main thread needs to execute list = null;
how much time the os needs to start executing the second thread and for the second thread to reach the point where it calls func(list);
From your observation the second thread needs more time to reach the point where func(list); is executed than the main thread needs to execute list = null;
If I remember Java correctly, it changes the value for user defined classes. So if you use primitive data types and already defined classes like int, string, etc then it wont cause you this problem. But here you are using your own class so its passed by reference for some reason.

WeakReferenced object is not garbage collected after calling System.gc()

I am a fresh new learner of Java. I'm now learning the concept of WeakReference. I came across a problem which probably looks stupid but I just wanna figure out the reason. The problem is: according to Java doc, "Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed."
So I did this small test:
import java.lang.ref.WeakReference;
public class A {
public static void main(String[] args) {
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
A a1 = wr.get();
System.out.println(a);
System.out.println(a1);
try {
System.gc();
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(a1);
}
#Override
protected void finalize( ) {
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}
However, I noticed that after GC running, wr.get() could still return object which I expected null, and the method finalize() was not invoked. So what went wrong? Thanks for your kind help in advance! :)
The premise of your test is flawed. System.gc() is only a hint to run the garbage collector. It is frequently ignored.
From the 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.
(Emphasis mine)
In future, you may use the VM options -verbose:gc and -XX:+PrintGCDetails to see what the garbage collector is doing.
More importantly, you are also very quickly taking the reference out of the weak reference and putting it back into a strong reference:
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null; // no strong references remain
A a1 = wr.get(); // the instance now has a strong reference again
Unless garbage collection occurs between these exact two instructions, the object will not be garbage collected.
If you remove a1, your code behaved as you would expect when I ran it (though, because of the first part of my answer, your mileage may vary):
class A
{
public static void main(String[] args)
{
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
System.out.println(a);
try {
System.gc(); // instance of A is garbage collected
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(wr.get());
}
#Override
protected void finalize( )
{
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}
Firstly, System.gc() does not ensure a garbage collection. Instead, it's just a hint that "It's a good time to run garbage collection".
Secondly, in your code when you put A a1 = wr.get(); before calling System.gc(), it creates a new strong reference to the same object referenced by a, thus even if garbage collection runs, your object will not be garbage collected.
As we have two tasks in hand
Ensure garbage collection
Don't keep any strong reference to the object you want to be garbage collected
Let's do little modification to your code
public class A {
public static void main(String[] args) {
A a = new A();
WeakReference<A> wr = new WeakReference<>(a);
a = null;
// A a1 = wr.get(); Removing this, this does our 2nd task
System.out.println(a);
// System.out.println(a1); Removing this as a1 does not exists anymore
try {
while (null != wr.get()) { // 1st task done, the loop ensures sending the hint until your object collected
System.gc();
// Thread.sleep(10000); it does not have impact
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(wr.get()); // Obviously prints null
}
#Override
protected void finalize() {
System.out.println(Thread.currentThread().getName() + ": See ya, nerds!");
}
}

Why is 'create' asynchronous?

I was told, that creating a new instance is always an async message; but I don't understand why.
e.g.:
Foo myFoo = new Foo();
Here I will have to wait until the constructor finishes and returns my new object. But doesn't asynchronous mean, that I go on independently (no waiting) - like starting a thread?
I was told, that creating a new instance is always an async message;
Sorry, I have to say that either you heard it wrong or you were told something that is wrong. But first off, we should get some terminology straight. The term "async" or "asynchronous" means that the invocation returns immediately to the caller. We can easily demonstrate that this is not true with a constructor, with a simple experiment [1]. In other words, the constructor must return for the caller to make any progress.
Starting a thread is indeed asynchronous. The call to Thread.start() returns immediately and at some later point in time the thread actually starts running and executing the run() method.
1 The Experiment
Consider your class (for illustration only) is like below:
Foo.java
class Foo {
Foo() throws InterruptedException {
while (true) {
System.out.println("not returning yet ...");
Thread.sleep(2000);
}
}
public static void main(String[] args) throws InterruptedException {
Foo foo = new Foo();
}
}
If you compiled and run this class (I used Java 8 on my Mac, but that is not a requirement). As expected, this class runs forever producing the output every 2 seconds:
not returning yet ...
not returning yet ...
not returning yet ...
not returning yet ...
Note that the sleep call was added just to make it bearable. You could try this experiment without it, but then your program will overwhelm one of the CPU's by stressing it to 100%.
If, while it is running, you took a thread dump (for example, by using the command jstack), you see something like below (curtailed for brevity):
"main" #1 prio=5 os_prio=31 tid=0x00007f9522803000 nid=0xf07
waiting on condition [0x000000010408f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at Foo.<init>(Foo.java:5)
at Foo.main(Foo.java:9)
Regardless of the state of the thread (RUNNABLE, BLOCKED, WAITING, TIMED_WAITING), you will always see (take various thread dumps to see what this means) you will always see these two lines:
at Foo.<init>(Foo.java:5)
at Foo.main(Foo.java:9)
which means that the caller (in this case, the main thread) will never make any progress. And since this constructor never returns, no progress happens.
I was told, that creating a new instance is always an async message;
No, java constructors doesn't have implyed synchronization. Anyway, you can have concurrency issues within it. There is not guarantee that all the fields are initialized after the constructor call.
Here I will have to wait until the constructor finishes and returns my new object. But doesn't asynchronous mean, that I go on independently (no waiting) - like starting a thread?
Nope, you don't have to wait. You can access the object within another thread.
I suggest you to read this thread.
Example for concurrent access to an object while the constructor is still executing:
public class Demo {
private volatile int constructionCounter;
private volatile String string;
public Demo() throws InterruptedException {
super();
assert this.constructionCounter == 0;
this.constructionCounter++;
// From this point on, there's no way the constructionCounter can ever be != 1 again, because the constructor will never run more than once, concurrently or otherwise.
assert this.constructionCounter == 1;
final Demo newInstance = this;
Thread t = new Thread( new Runnable() {
public void run() {
// Access new instance from another thread.
// Race condition here; may print "Hello null" or "Hello World" depending on whether or not the constructor already finished.
System.out.println("Hello " + newInstance.getString());
}
});
t.start();
this.setString( "World!" );
}
public String setString( String str ) {
this.string = str;
}
public String getString() {
return this.string;
}
}
Note that this is only ever possible if and when the constructor itself somehow hands this out to another thread.

can java 8 lambdas cause memory leaks?

well I found this code in a blog, and wanted to understand why it would cause a memory leak, if it is potential of causing a memory leak.
class Test {
public static void main(String[] args) {
Runnable runnable = new EnterpriseBean()
.runnable();
runnable.run(); // Breakpoint here
}
}
#ImportantDeclaration
#NoMoreXML({
#CoolNewValidationStuff("Annotations"),
#CoolNewValidationStuff("Rock")
})
class EnterpriseBean {
Object[] enterpriseStateObject =
new Object[100_000_000];
Runnable runnable() {
return () -> {
System.out.println("Hello from: " + this);
};
}
}
The provided code does not have a memory leak, and the blog entry from which it is drawn does not say otherwise. What it says is that the object returned by EnterpriseBean.runnable() has much (much) larger state than you might naively expect, and that that state cannot be garbage collected before the Runnable itself is.
However, there is nothing in that code that would prevent the Runnable from eventually being collected, and at that time all the extra state will be eligible for collection, too.
So no, the code is not an example of a memory leak, and does not suggest a means to produce one.

Understanding the Java stack

There is this code:
public class Main {
public static void main(final String[] args) throws Exception {
System.out.print("1");
doAnything();
System.out.println("2");
}
private static void doAnything() {
try {
doAnything();
} catch (final Error e) {
System.out.print("y");
}
}
}
And there is the output:
1yyyyyyyy2
Why does it print "y" eight times and no more. How can Java call println() when StackOverflowError encountered?
Here you are catching Error and not Exception in which case your program would have crashed.
If you try this code (modified to add a static counter)
public class StackError {
static int i = 1;
public static void main(final String[] args) throws Exception {
System.out.print("1");
doAnything();
System.out.println("2");
}
private static void doAnything() {
try {
i++;
// System.out.println(i);
doAnything();
} catch (Error e) {
System.out.print("y"+i+"-");
}
}
}
Output
1y6869-2
So, it has got stackerror 6869 times(changes for different runs) and the last value is printed. If you just print the y as you did earlier then it might the case that the output is getting bufferred and not getting flushed as it is not a println.
Update
The System.out.println internally calls the PrintStream which is buffered. You don't loose any data from the buffer, it gets all written to the output( terminal in your case) after it fills up, or when you explicitly call flush on it.
Coming back to this scenario, it depends on the internal dynamics of how much the stack is filled up and how many print statements were able to get executed from the catch in doAnything() and those number of characters were written to the buffer. In the main back it finnally get's printed with the number 2.
javadoc reference to buffered streams
My bet is that by invoking print in the catch block you force another StackOverflowError that is caught by the outer block. Some of these calls will not have enough stack for actually writing the output stream.
The JLS says that:
Note that StackOverflowError, may be thrown synchronously by method
invocation as well as asynchronously due to native method execution
or Java virtual machine resource limitations.
The Java SE platform permits a small but bounded amount of execution
to occur before an asynchronous exception is thrown.
The delay noted above is permitted to allow optimized code to detect
and throw these exceptions at points where it is practical to handle
them while obeying the semantics of the Java programming language. A
simple implementation might poll for asynchronous exceptions at the
point of each control transfer instruction. Since a program has a
finite size, this provides a bound on the total delay in detecting an
asynchronous exception.
The first time the StackOverFlowError occurs, the call to the last doAnything() is cancelled and the control is returned to the catch block from the last doAnything().
However, because the stack is still practically full, the simple fact of calling System.out.print("y") will causes another StackOverflowError because of the need of pushing some value on the stack and then make a call to the function print().
Therefore, another StackOverflowError occurs again and the return is now returned on the catch{} block of the previous doAnything(); where another StackOverflowError will happens because the need of stack space required to do a single call to System.out.println("y") is greater than the amount of space liberated from returning a call from doAnything().
Only when there will be enough space on the stack to execute a call to System.out.print("y") that this process will stop and a catch block will successfully complete. We can see that by running the following piece of code:
public class Principal3b {
static int a = 0;
static int i = 0;
static int j = 0;
public static void main(String[] args) {
System.out.println("X");
doAnything();
System.out.println("Y");
System.out.println(i);
System.out.println(j);
}
private static void doAnything() {
a++;
int b = a;
try {
doAnything();
} catch (final Error e) {
i++;
System.out.println(a);
System.out.println(b);
j++;
}
}
}
Notice that a println(a) is used instead of a print(a); therefore a new line should be printed after each value of a if everything runs OK.
However, when I run it, I get the following result:
X
62066206620662066206620662066206
6190
Y
17
1
This means that there have been 17 attempts ro run the catch block. Of these catch block executions, 9 are unable to print anything before generating themselves a StackOverflowError; 7 are able to print the value of 6190 but are unable to print a newline after it before themselves rising an error again and finally, there is one that is able to both print the value of 6190 and the newline after it; therefore finally permitting its catch block to complete without any new StackOverflowError and return gracefully up the calls stack.
As we are dealing with StackOverflowError, these numbers are only an example and will vary greatly not only between machines but also between executions and the simple fact of adding or removing any kind of instructions should also change these values. However, the pattern seen here should remains the same.
One thing is clear that System.out.print("y"); in catch creates this puzzle. If we change the code as
static int n;
public static void main(final String[] args) throws Exception {
System.out.println("1");
doAnything();
System.out.println(n);
}
private static void doAnything() {
try {
doAnything();
} catch (Error e) {
n++;
}
}
it prints
1
1
Well the no. of times the stack overflow error is hit is undefined. However, the JVM allows you to recover from StackOverflowError error and continue execution of the system normally.
It is proved by the following code:
public class Really {
public static void main(final String[] args) throws Exception {
System.out.print("1");
doAnything();
System.out.println("2");
}
private static void doAnything() {
try {
throw new StackOverflowError();
//doAnything();
}
catch(final Error e){
System.out.print("y");
}
}
}
Note however, as #Javier said, the StackOverflowError is thrown by the JVM synchronously or asynchronously(which means it can be thrown by another thread, possibly a native thread) which is why it is not possible to get the stack trace of the error. The no. of times the thread(s) hit the catch() block is undefined.
In addition, Objects of type Error are not Exceptions objects they represent exceptional conditions.
Errors represent unusual situations that are not caused by program errors,
usually does not normally happen during program execution, such as JVM running out of memory.
Although they share a common superclass Throwable, meaning both can be thrown, it can
be placed in a catch but generally not supposed to be caught, as they represent
rare, difficult-to-handle exceptional conditions.
Stack overflow.
You are only printing on exception,in the meantime the program recurses into overflow.
At which point this occurs depends on individual systems, memory, etc.
What is the purpose of the program?

Categories