Java-Gaming.org Hi !
Featured games (90)
games approved by the League of Dukes
Games in Showcase (777)
Games in Android Showcase (231)
games submitted by our members
Games in WIP (856)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Using the sun.misc.Unsafe class to do crazy stuff with the JVM  (Read 17423 times)
0 Members and 1 Guest are viewing this topic.
Offline ShadedVertex
« Posted 2015-12-19 05:24:06 »

I recently discovered the sun.misc.Unsafe class. Apparently it can be used to manage memory manually, create instances of classes with only private constructors and creating super-large arrays. Is it advisable to use this class? I mean, the class name itself seems to warn developers against using it. But if I do know how to use it the right way, is it advisable to use it to manage memory and all?
Offline Phased
« Reply #1 - Posted 2015-12-19 05:38:50 »

If you are starting to think about memory management using Unsafe, you may as well go to C++.
Offline chrislo27
« Reply #2 - Posted 2015-12-19 05:41:54 »

As with Phased's message above, it's also not part of the standard JVM, that is, different operating systems will have the sun packages implemented differently, and your code will throw a ClassNotFoundError if the code runs on a non-Sun supported JVM. This essentially defeats the purpose of Java (being able to run on all platforms seamlessly).

Here's a fairly good SO question and answer to this same question.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ShadedVertex
« Reply #3 - Posted 2015-12-19 05:54:26 »

If you are starting to think about memory management using Unsafe, you may as well go to C++.

The reason why I don't like C++ is that its syntax is quirky and inconvenient (in my opinion). I want Java's developer-friendly syntax and I'd like to manage memory manually within Java.
Offline ShadedVertex
« Reply #4 - Posted 2015-12-19 05:55:50 »

As with Phased's message above, it's also not part of the standard JVM, that is, different operating systems will have the sun packages implemented differently, and your code will throw a ClassNotFoundError if the code runs on a non-Sun supported JVM. This essentially defeats the purpose of Java (being able to run on all platforms seamlessly).

Here's a fairly good SO question and answer to this same question.

Is there a way around this? Shouldn't it be fine, as long as the device has the latest version of Java installed?
Offline chrislo27
« Reply #5 - Posted 2015-12-19 06:03:21 »

Is there a way around this? Shouldn't it be fine, as long as the device has the latest version of Java installed?

The sun packages aren't technically part of Java, per say. They may be removed at any time, Oracle could stop supporting it and just ditch it, rename it to com.oracle.*, etc. The point is is that it's unsupported and should really be depended on.

If you want to fool around with memory management and special classes, go for it. We're just not recommending you use it in a project such as a game where other people will use it due to its unpredictable behaviour and future changes.
Offline Phased
« Reply #6 - Posted 2015-12-19 06:05:50 »

The reason why I don't like C++ is that its syntax is quirky and inconvenient (in my opinion). I want Java's developer-friendly syntax and I'd like to manage memory manually within Java.

I find C++ pretty much similar to Java when you scrap off pointers in C++.

By adding the use of Unsafe to your code, you are probably not even going to notice a performance increase, if that is what you are hoping for.

You are pretty much saying no to one of Java's best features and rolling with your own.

If you are thinking it will increase the performance of your terrain generation, its probably going to either give worse performance or the same performance.

You should continue to improve, you will find that your performance issues are more yourself then the limitations of Java.
Offline ShadedVertex
« Reply #7 - Posted 2015-12-19 06:32:35 »

It's not about terrain generation. I just read up about Unsafe and thought that it could be useful. Besides, the ability to manually manage memory in C++ is what makes C++ so powerful, mostly. Wouldn't it be great if Java could do the same thing? I mean, in Java-based games you could experience performance issues because the garbage collector is trying to do its job. It happens in Minecraft too, sometimes. Does setting an object to null and then calling System.gc() count as freeing memory? From what I know, System.gc() only suggests that the garbage collector should run and does not FORCE the garbage collector to run.

Offline ShadedVertex
« Reply #8 - Posted 2015-12-19 06:34:29 »

I got this from jaxenter.com:

Quote
unsafe is the only way so far to write high performance/ gc free code in java.

Is this true?

EDIT: I also got this from an interview with some official Oracle dudes:

Quote
Peter:  Our main use case is off heap, shared, persistent data structures. The benefit is that we can use shared data between processes as fast as sharing data between threads. We can also persist that data in bursts of 30 million updates per second. One of our clients writes 24 million market data events per second during peak periods in the market. As the code is GC free, this is done without pauses. In the past, this might have only been achieved using C++ or C, but Unsafe allows us to get the performance of C where we need it but the portability and ease of development of Java.
Offline Phased
« Reply #9 - Posted 2015-12-19 06:39:23 »

You shouldnt need to call System.gc(); ever.

It will run its self when needed.

To what I know (also from the above post), you have to manually delete the memory you allocate using Unsafe, this means, you need to add deconstructors like methods to every Java class you use, if you simply let a reference to an object go, the GC will never clean it up, meaning you got a memory leak.

I will stand by my "If you are starting to require memory management in Java, you should change languages". You are probably going to be limited by something else before memory management in java is your concern.

You are adding an extra level of complexion to your code, where you do not require it.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ShadedVertex
« Reply #10 - Posted 2015-12-19 06:44:05 »

You shouldnt need to call System.gc(); ever.

It will run its self when needed.

To what I know (also from the above post), you have to manually delete the memory you allocate using Unsafe, this means, you need to add deconstructors like methods to every Java class you use, if you simply let a reference to an object go, the GC will never clean it up, meaning you got a memory leak.

I will stand by my "If you are starting to require memory management in Java, you should change languages". You are probably going to be limited by something else before memory management in java is your concern.

You are adding an extra level of complexion to your code, where you do not require it.



Apparently Oracle will be introducing a safe version of Unsafe in Java 9 as part of Project Jigsaw. I think there was a talk about that. Most Java developers don't actually use Unsafe, but some do.

Anyway, yeah, I get the point (get the pun? Memory management...POINTers...? I'm so funny). I guess I'm just gonna forget about Unsafe, then. Still, it's a pretty interesting class.
Offline Stranger
« Reply #11 - Posted 2015-12-19 07:15:12 »

Hi,

Some time ago I was inspired by Unsafe too.

But I've resisted. Smiley

Just look at this :

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
    public static long sizeOf( Object object )
    {
        return getUnsafe().getAddress(
                normalize( getUnsafe().getInt( object, 4L ) ) + 12L );
    }

    private static long normalize( int value )
    {
        if ( value >= 0 )
        {
            return value;
        }

        return ( ~0L >>> 32 ) & value;
    }

    public static long toAddress( Object obj )
    {
        Object[] array = new Object[]{obj};
        long baseOffset = getUnsafe().arrayBaseOffset( Object[].class );

        return normalize( getUnsafe().getInt( array, baseOffset ) );
    }

    public static Object fromAddress( long address )
    {
        Object[] array = new Object[]{null};
        long baseOffset = getUnsafe().arrayBaseOffset( Object[].class );
        getUnsafe().putLong( array, baseOffset, address );

        return array[ 0 ];
    }


Isn't it wonderful?

But, try to keep away from it.

Anton
Offline Roquen

JGO Kernel


Medals: 518



« Reply #12 - Posted 2015-12-19 13:10:16 »

You shouldnt need to call System.gc(); ever.
So program should ever want to to perform a full GC at a time of it's choosing and should always let it happen at some unknowable point in the future outside of its control?  For games, say at points where there's a natural pause in gameplay anyway?

Quote
... you have to manually delete the memory you allocate using Unsafe,
Not allocate once, keep forever memory.  A common use-case.

The "real" problem with unsafe usage is:  behavior may change across release (distribute a specific VM with program solves this one).  Undocumented, so you have to be very careful.  And you can put yourself into untested (another be very careful) cases of VM behavior.

Quote
this means, you need to add deconstructors like methods to every Java class you use,
In addition the above "not necessarily", there's allocations naturally dominated by a container.

Quote
..if you simply let a reference to an object go, the GC will never clean it up, meaning you got a memory leak.
GCed objects can memory leak as well.  In either case poor design will bite you.

Quote
I will stand by my "If you are starting to require memory management in Java, you should change languages".
Possibly...depends on a person's knowledge of, comparative productivity in the languages in question and the overall "problem space" of the program.  Many factors here.

Quote
You are probably going to be limited by something else before memory management in java is your concern.
Problem space and programmer's understanding of it.  On the whole, you're way overgeneralizing.

There are things you can't do without Unsafe.
Offline Phased
« Reply #13 - Posted 2015-12-19 13:27:11 »

@Roquen

My reply was more directly towards ShadedVertex, I know in certain scenarios you will probably want to use Unsafe.

My assumption was he wanted to code his entire game using Unsafe for memory management, where in the entire game, he will probably being deallocating a fair bit, which would pretty much mean he needs a deconstructor in every class.

My "If you are starting to require memory management in Java, you should change languages" was more towards him making a game in Java, I feel like his going to be limited by other stuff before he gets limited by the memory management. He also has a lot more other things he needs to learn in OpenGL before he adds the use of Unsafe to manage his memory.

At no point do I see ShadedVertex in the near future require the use of Unsafe, and most likely majority of the users on this forum.

@theagentd if you see this, do you actually use Unsafe to manage any memory at all in We Shall Wake?
Offline theagentd
« Reply #14 - Posted 2015-12-19 15:03:18 »

@Phased
No, we don't use Unsafe directly in WSW.

@Roquen
We do however try to call System.gc() after loading since our loading code does generate a bit of garbage and it's a good time to signal the GC that we're okay with a garbage collection if it feels like it. =P

Myomyomyo.
Offline Roquen

JGO Kernel


Medals: 518



« Reply #15 - Posted 2015-12-19 18:19:20 »

Exactly my point.  At any natural pause in gameplay, ideally one could say "Do full GC...NOW!".
Offline princec

« JGO Spiffy Duke »


Medals: 1060
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #16 - Posted 2015-12-19 18:23:30 »

I used to think that way... but I now see that the GC is basically so fast and efficient it generally tends to be totally unnoticeable outside of ordinary random noise jitter if just left the hell alone, especially when it's left to tune itself with target collection times (I set mine to 3ms).

Cas Smiley

Offline theagentd
« Reply #17 - Posted 2015-12-19 19:08:30 »

Exactly my point.  At any natural pause in gameplay, ideally one could say "Do full GC...NOW!".

Yup. Making sure that your game loop generates minimal garbage, and calling System.gc() whenever they're not noticeable is good enough. We generate a few kilobytes of garbage each frame (most of it being debugging strings for profiling), and this buildup takes several minutes before a fast, small GC pass can kick in and remove it all in a few milliseconds without a full stop-the-world GC being needed for a long time. At load time go crazy with garbage if it's faster to write; the call to System.gc() before you start the level will (most likely) clean it all up giving the game loop a garbage-free start.

Myomyomyo.
Offline Archive
« Reply #18 - Posted 2015-12-19 20:40:33 »

Exactly my point.  At any natural pause in gameplay, ideally one could say "Do full GC...NOW!".

Yup. Making sure that your game loop generates minimal garbage, and calling System.gc() whenever they're not noticeable is good enough. We generate a few kilobytes of garbage each frame (most of it being debugging strings for profiling), and this buildup takes several minutes before a fast, small GC pass can kick in and remove it all in a few milliseconds without a full stop-the-world GC being needed for a long time. At load time go crazy with garbage if it's faster to write; the call to System.gc() before you start the level will (most likely) clean it all up giving the game loop a garbage-free start.
While debugging my game Shard Master, I found out (might not be true) that the garbage collection acts out on Linux for some reason and it makes the memory usage ridiculously high.

Can anyone confirm this? Or was this just a fluke

Offline gouessej
« Reply #19 - Posted 2015-12-20 22:16:56 »

My "If you are starting to require memory management in Java, you should change languages" was more towards him making a game in Java, I feel like his going to be limited by other stuff before he gets limited by the memory management. He also has a lot more other things he needs to learn in OpenGL before he adds the use of Unsafe to manage his memory.
It's still up to you to manage the memory allocated on the native heap (not on the Java heap) typically used by direct NIO buffers. The original poster seems to know the JEP 260, I advise him to forget the Unsafe class and to use sun.misc.Cleaner until a replacement solution is provided. I explained all this with more details here.

In my humble opinion, forcing the garbage collection is a bad idea. If you don't keep references on useless objects, the garbage collector will do its job smartly most of the time. You can use the pauses in your game to make the most impacting cleanup.

Julien Gouesse | Personal blog | Website | Jogamp
Offline Roquen

JGO Kernel


Medals: 518



« Reply #20 - Posted 2015-12-21 08:24:05 »

Quote
forcing the garbage collection is a bad idea <snip> You can use the pauses in your game to make the most impacting cleanup.
The way to "use the pause" is to force the GC to run.  Otherwise it's outside of the programmer's control.  These are contradictory statements.

Note that
System.gc()
really isn't the way to force a full GC.
Offline princec

« JGO Spiffy Duke »


Medals: 1060
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #21 - Posted 2015-12-21 09:28:23 »

(Expanding on Roquen's comment: the best way is to attempt to allocate a massive array and catch the OOME)

Cas Smiley

Offline Roquen

JGO Kernel


Medals: 518



« Reply #22 - Posted 2015-12-21 09:40:50 »

Yeah, I didn't say "how" because it's fragile.  In theory a compiler can remove anything which doesn't change the meaning of the program...so it's possible that some compiler might be able to determine that the try block with allocate really big memory doesn't do anything and remove the whole thing.  So (again) in theory the try block would need to be written in such a way that it's difficult for the compiler to see that it has no side-effect.  The ideal situation would be for Java to acknowledge that programmers actually sometimes know what they are doing and expose a method to force a full-gc.
Offline ags1

JGO Kernel


Medals: 367
Projects: 7


Make code not war!


« Reply #23 - Posted 2015-12-21 11:20:04 »

Something like this?

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
public class ForceGC {

    private static Random RANDOM = new Random();
    //Read this from somewhere else; e.g. write it to a log if it's not zero
    //this is to avoid the compiler optimizing the array allocation
    public static long irrelevantStateField = 0;

    public static void main(String[] args) {
        gc();

    }

    private static void gc() {
        long[] tooBig = new long[10];
        try {
-           tooBig = new long[Integer.MAX_VALUE];
+          tooBig = new long[Integer.MAX_VALUE - 100];
            tooBig[RANDOM.nextInt()] = RANDOM.nextInt();
        } catch (OutOfMemoryError expected) {
            System.out.println("We have forced GC!");
        }
        irrelevantStateField = tooBig[RANDOM.nextInt(tooBig.length)];
    }
}

Offline princec

« JGO Spiffy Duke »


Medals: 1060
Projects: 3
Exp: 20 years


Eh? Who? What? ... Me?


« Reply #24 - Posted 2015-12-21 11:34:28 »

Pretty much. Though to avoid the JVM shortcutting GC altogether (a potential optimisation) if you attempt to allocate something that's larger than the actual max heap size you might want to pick an array size based on what the runtime says is actually possible.

Cas Smiley

Offline ags1

JGO Kernel


Medals: 367
Projects: 7


Make code not war!


« Reply #25 - Posted 2015-12-21 12:15:50 »

You are referring to the header fields that can be added to an array?

http://stackoverflow.com/questions/31382531/why-i-cant-create-an-array-with-large-size

I edited my suggestion to take this into account. I also outputted the exception message in the catch block ,and confirmed my original code returned:

Requested array size exceeds VM limit

But the corrected code returns:

Java heap space

Thanks for spotting that!

Offline basil_

« JGO Bitwise Duke »


Medals: 418
Exp: 13 years



« Reply #26 - Posted 2015-12-21 16:18:53 »

i use something similar. this is from
it.unimi.dsi.Util
:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public static void compactMemory()
{
  try
  {
    final byte[][] unused = new byte[128][];

    for(int i = unused.length; i-- != 0; )
      unused[i] = new byte[2000000000];
  }
  catch(OutOfMemoryError itsWhatWeWanted){}

  System.gc();
}


just a hint : this works on hotspot. a VM like excelsior jet does not like that!
Offline theagentd
« Reply #27 - Posted 2015-12-21 17:25:19 »

In a fun twist, it looks like I'll actually be basing my new rendering system on unsafe access to JEmalloc and mapped OpenGL buffers to avoid the overhead of ByteBuffer objects being created all the time. I've created a "smart" byte buffer class that can expand automatically without generating any garbage using JEmalloc and did some benchmarking putting floats in buffers.


Legend:

N = normal access
S = "smart" access

H = ByteBuffer.allocate(), written to using putFloat(index, float)
D = JEmalloc.je_malloc(), written to using putFloat(index, float)
U = JEmalloc.nje_malloc(), written to using MemoryUtil.memPut***())

Result is in million puts per second. I'm guessing a bit here, but the theoretical maximum of the CPU should be 1 instruction per clock, or 3900MHz (turboing) = 3900 million puts per second. My RAM has a theoretical bandwidth of 19 200 MB/sec (2400MHz DDR3), limiting me to 4 800 million 4-byte floats per second.

Results:

NH:  784.80 Mputs/sec
ND: 1898.02 Mputs/sec
NU: 2215.86 Mputs/sec
SH:  280.56 Mputs/sec
SD:  389.86 Mputs/sec
SU:  665.76 Mputs/sec


My smart buffer has around 1/4th as much throughput as a raw unsafe performance. =< But, my point is that using direct unsafe access is noticeably faster than going with direct ByteBuffers.

Myomyomyo.
Offline gouessej
« Reply #28 - Posted 2015-12-22 16:31:25 »

The way to "use the pause" is to force the GC to run.  Otherwise it's outside of the programmer's control.  These are contradictory statements.
I advise you to read my comments once more. It's the right time to manage the memory on the native heap, which is up to the programmer.

Note that
System.gc()
really isn't the way to force a full GC.
I know that, it's just an hint, I'm able to read the Java documentation... "Calling the gc method suggests".

Julien Gouesse | Personal blog | Website | Jogamp
Pages: [1]
  ignore  |  Print  
 
 

 
hadezbladez (292 views)
2018-11-16 13:46:03

hadezbladez (162 views)
2018-11-16 13:41:33

hadezbladez (293 views)
2018-11-16 13:35:35

hadezbladez (73 views)
2018-11-16 13:32:03

EgonOlsen (2154 views)
2018-06-10 19:43:48

EgonOlsen (2181 views)
2018-06-10 19:43:44

EgonOlsen (1368 views)
2018-06-10 19:43:20

DesertCoockie (1985 views)
2018-05-13 18:23:11

nelsongames (1627 views)
2018-04-24 18:15:36

nelsongames (2275 views)
2018-04-24 18:14:32
Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08

Deployment and Packaging
by gouessej
2018-08-22 08:03:45

Deployment and Packaging
by philfrei
2018-08-20 02:33:38

Deployment and Packaging
by philfrei
2018-08-20 02:29:55

Deployment and Packaging
by philfrei
2018-08-19 23:56:20

Deployment and Packaging
by philfrei
2018-08-19 23:54:46
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!