Win a copy of Pro Spring MVC with WebFlux: Web Development in Spring Framework 5 and Spring Boot 2 this week in the Spring forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Jeanne Boyarsky
  • Liutauras Vilda
Sheriffs:
  • Rob Spoor
  • Bear Bibeault
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:
  • Frits Walraven
  • Himai Minh

Java Memory Puzzle

 
Ranch Hand
Posts: 31
MyEclipse IDE
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Java Memory Puzzle
Instead of telling you some mystery of Java memory, it is time for you to put on your thinking caps. I had a discussion a few weeks ago with one of my subscribers of whether you should null your local variables, to make things easier for the garbage collector. His understanding was that the local variables will be stored on the stack and thus popped off at the end of the method call anyway, so nulling them was a waste of time. In almost all situations, he is right. However, he had a class that did something most peculiar, something like this:




When you run this you will always get an OutOfMemoryError, even though the local variable data is no longer visible outside of the code block.

So here comes the puzzle, that I'd like you to ponder about a bit. If you very politely ask the VM to release memory, then you don't get an OutOfMemoryError:




Copyright Heinz Kabutz 2009
Aristotelous 84, Korakies, Akrotiri, Chania, Crete, 73100, Greece




Why does this work?
 
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Don't know but:

is also failed, BUT:

works fine.
 
Dmitry Mamonov
Greenhorn
Posts: 28
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here is bytecode difference;

// Method descriptor #8 ()V
// Stack: 1, Locals: 3
public void f();
0 aload_0 this
1 getfield sys.JavaMemoryPuzzle.dataSize : int 24
4 newarray byte 8
6 astore_1
XX iconst_1 <<<difference
XX istore_1 i <<<difference
7 aload_0 this
8 getfield sys.JavaMemoryPuzzle.dataSize : int 24
11 newarray byte 8
13 astore_2 data2
14 return


My suggestion is:
when code walks out from nested {} block it will not assign null values to variables in such block.
We just will not see them in java code.

Second example of code works fine (marked with XX in bytecode list) cause
the value=1 is stored into variable name = "i" exactly into the same place (index=1)
where variable name="data" was stored before.
This breaks reference to first allocated array so it could be collected with GC.
 
Ranch Hand
Posts: 607
Firefox Browser Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Looks like the Garbage collector just does not get time to kick in - in the first case. In the case where you loop 10 times the garbage collector kicks in and does its work.

Of course the Garbage collector could run in the first case too - but mostly probably wound not get time. Maybe if you run a million times you might see that it runs fine some times - with no exception!

P.S - Setting it to null would not help either.
 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To me this sounds like JVM implementation issue in the way they handle stack. Once local variable out of scope stack pointer decremented but the reference still exists causing GC to not clear this array object. By adding for loop (or an other local variable in between) we are forcing JVM to use prior Stack location (where data byte array reference used to be) and now no reference to that allocated memory.

Take a look at my code (I used to test my theory):



I also tested this by declaring byte array allocation in a function and stack handling seems to work fine in this scenario.

Thanks,
Chakri
 
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Then why the below code is working.

public class Testting {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);

public void f() {
{
byte[] data = new byte[dataSize];
}
String strTest = new String();
byte[] data2 = new byte[dataSize];
}

public static void main(String[] args) {
Testting jmp = new Testting();
jmp.f();
System.out.println("DONE");
}
}
 
Srinivasa Chebrolu
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Then why the below code is working.



Thats the whole point. The moment you add local variable before 2nd memory allocation you use last stack location (which was holding reference to first byte array 'data') and with local variable introduction and assignment you freeing 'data' obect reference, no reference to 'data' means that object can be GC'd.

 
I'm not dead! I feel happy! I'd like to go for a walk! I'll even read a tiny ad:
Thread Boost feature
https://coderanch.com/t/674455/Thread-Boost-feature
reply
    Bookmark Topic Watch Topic
  • New Topic