Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (489)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (553)
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  
  Is it possible to pin an Object using JNI global references  (Read 1876 times)
0 Members and 1 Guest are viewing this topic.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Posted 2009-08-13 01:35:35 »

I really need to do some crazy hackery, but it requires certain objects not being moved around the heap. I was thinking... could these global references be used?

http://java.sun.com/docs/books/jni/html/refs.html
"5.1.2 Global References" (Scroll to about 30% of the page)

Anybody experience? Anybody with a C compiler setup to actually work (mine is teasing me) that could copy and paste this?


To determine whether the object moved, thus to track the pointer of an Object, you can use this hackery code:
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  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import sun.misc.Unsafe;

public class OneOfTheNativeHacks
{
   private final static Unsafe   unsafe;
   private static final long     BITS;
   private static final long     OFF;
   private static final Object[] holder = new Object[1];

   static
   {
      try
      {
         ByteBuffer buffer = ByteBuffer.allocateDirect(1);
         Field unsafeField = buffer.getClass().getDeclaredField("unsafe");
         unsafeField.setAccessible(true);
         unsafe = (Unsafe) unsafeField.get(buffer);
         unsafeField.setAccessible(false);

         buffer.flip();
      }
      catch (Exception exc)
      {
         exc.printStackTrace();
         throw new InternalError();
      }

      BITS = unsafe.addressSize() * 8;
      OFF = unsafe.arrayBaseOffset(holder.getClass());
   }

   public static final synchronized long getObjectAddress(Object obj)
   {
      holder[0] = obj;
      if (BITS == 32)
         return unsafe.getInt(holder, OFF);
      if (BITS == 64)
         return unsafe.getLong(holder, OFF);
      throw new IllegalStateException();
   }
}

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline princec

JGO Kernel


Medals: 367
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #1 - Posted 2009-08-13 09:38:45 »

Sounds like awful hackery. What naughtiness are you up to?

Cas Smiley

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2009-08-13 11:37:58 »

Structs.

They mustn't move.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 367
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #3 - Posted 2009-08-13 11:48:13 »

Ow, very naughty. What if they get stuck in eden?

Cas Smiley

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #4 - Posted 2009-08-13 11:50:33 »

Nah, I'm faking objects. I'm writing them (the object headers) at some allocated memory location, and they shouldn't move *into* the heap.

For example: I have a float[] and a FloatBuffer that point to the same memory location. It is the ultimate solution to the performance problems with FloatBuffers, while still being able to send them to the GPU without copying the darn thing. It all works very nicely, until the GC kicks in and moves my float[] into the heap.

Now if anybody could give the code a whirl (on the mentioned URL) I'd be grateful!

It would even be enough to force the GC not to run, but from what I understand, that's impossible, unless you're not calling 'new'... anywhere, maybe? Hard to guarantee that if my code would be in a 3rd party lib and somebody else would use it, as "x="+x; would suddenly potentially separate your float[] from your FloatBuffer.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline pjt33
« Reply #5 - Posted 2009-08-13 12:44:30 »

Now if anybody could give the code a whirl (on the mentioned URL) I'd be grateful!
The code in the page you link to creates a reference to String.class. What kind of tests do you expect to perform on it?

Here's a little demo, but I don't think it proves anything useful.

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  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
pjt33@agape:/tmp/jni/$ cat testPin.c
#include <jni.h>

JNIEXPORT jclass JNICALL Java_TestPin_pinStringClass(JNIEnv * env, jclass clazz)
 {
     static jclass stringClass = NULL;

     if (stringClass == NULL) {
         jclass localRefCls =
             (*env)->FindClass(env, "java/lang/String");
         if (localRefCls == NULL) {
             return NULL; /* exception thrown */
         }
         /* Create a global reference */
         stringClass = (*env)->NewGlobalRef(env, localRefCls);

         /* The local reference is no longer useful */
         (*env)->DeleteLocalRef(env, localRefCls);

         /* Is the global reference created successfully? */
         if (stringClass == NULL) {
             return NULL; /* out of memory exception thrown */
         }
     }

pjt33@agape:/tmp/jni/$ gcc -o libtestPin.so -shared -I/usr/lib/jvm/jdk/include -I/usr/lib/jvm/jdk/include/linux testPin.c -static
pjt33@agape:/tmp/jni/$ cat TestPin.java
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import sun.misc.Unsafe;

public class TestPin
{
        public static native Class pinStringClass();
        static
        {
                System.loadLibrary("testPin");
        }

        public static void main(String[] args) throws Exception
        {
                Class foo = pinStringClass();
                System.out.println(getObjectAddress(foo));
                // Churn to force some GC.
               ArrayList<String> list = new ArrayList<String>();
                for (int i = 0; i < 1000000; i++)
                    list.add((String)foo.newInstance());
                System.out.println(getObjectAddress(foo));
        }

   private final static Unsafe   unsafe;
   private static final long     BITS;
   private static final long     OFF;
   private static final Object[] holder = new Object[1];

   static
   {
      try
      {
         ByteBuffer buffer = ByteBuffer.allocateDirect(1);
         Field unsafeField = buffer.getClass().getDeclaredField("unsafe");
         unsafeField.setAccessible(true);
         unsafe = (Unsafe) unsafeField.get(buffer);
         unsafeField.setAccessible(false);

         buffer.flip();
      }
      catch (Exception exc)
      {
         exc.printStackTrace();
         throw new InternalError();
      }

      BITS = unsafe.addressSize() * 8;
      OFF = unsafe.arrayBaseOffset(holder.getClass());
   }

   public static final synchronized long getObjectAddress(Object obj)
   {
      holder[0] = obj;
      if (BITS == 32)
         return unsafe.getInt(holder, OFF);
      if (BITS == 64)
         return unsafe.getLong(holder, OFF);
      throw new IllegalStateException();
   }

}
pjt33@agape:/tmp/jni/$ javac TestPin.java
TestPin.java:4: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
import sun.misc.Unsafe;
               ^
TestPin.java:25: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
   private final static Unsafe   unsafe;
                        ^
TestPin.java:37: warning: sun.misc.Unsafe is Sun proprietary API and may be removed in a future release
         unsafe = (Unsafe) unsafeField.get(buffer);
                   ^
3 warnings
pjt33@agape:/tmp/jni/$ LD_LIBRARY_PATH=. java -verbose:gc TestPin
-1321504640
[GC 896K->664K(5056K), 0.0059970 secs]
[GC 1560K->1456K(5056K), 0.0055870 secs]
[GC 2352K->2351K(5056K), 0.0064100 secs]
[GC 3247K->3247K(5056K), 0.0052960 secs]
[GC 4143K->4141K(5056K), 0.0060390 secs]
[GC 5037K->5036K(5960K), 0.0048390 secs]
[Full GC 5036K->4462K(5960K), 0.0485570 secs]
[GC 5358K->5356K(8400K), 0.0053860 secs]
[GC 6024K->6015K(8400K), 0.0046480 secs]
[GC 6911K->6911K(8400K), 0.0040350 secs]
[GC 7807K->7805K(8784K), 0.0063760 secs]
[Full GC 7805K->7288K(8784K), 0.0641510 secs]
[GC 8184K->8182K(13108K), 0.0054620 secs]
[GC 10241K->10240K(13108K), 0.0070920 secs]
[GC 11136K->11135K(13108K), 0.0062270 secs]
[GC 12031K->12029K(13108K), 0.0061340 secs]
[GC 12925K->12924K(13876K), 0.0064870 secs]
[Full GC 12924K->12149K(13876K), 0.0930100 secs]
[GC 15366K->15365K(21852K), 0.0107320 secs]
[GC 16837K->16836K(21852K), 0.0101650 secs]
[GC 18308K->18306K(21852K), 0.0291330 secs]
[GC 19778K->19778K(21852K), 0.0105530 secs]
[GC 20703K->20689K(22236K), 0.0078490 secs]
[Full GC 20689K->19304K(22236K), 0.1392640 secs]
[GC 24098K->24097K(34608K), 0.0165440 secs]
[GC 26273K->26272K(34608K), 0.0168730 secs]
[GC 28448K->28447K(34608K), 0.0402030 secs]
[GC 30623K->30622K(34608K), 0.0166760 secs]
[GC 30667K->30648K(34608K), 0.0016900 secs]
[Full GC 30648K->28903K(34608K), 0.1865680 secs]
[GC 36094K->36093K(51824K), 0.0243340 secs]
[GC 39357K->39355K(51824K), 0.0254730 secs]
[GC 42619K->42618K(51824K), 0.0263010 secs]
-1321504640
pjt33@agape:/tmp/jni/$
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 783
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #6 - Posted 2009-08-13 12:51:19 »

Yeah well, sorry, not a copy-and-paste, just storing a pointer to a passed object in a global ref, just like the String.class is stored.

Sorry.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline pjt33
« Reply #7 - Posted 2009-08-13 12:53:21 »

Yeah well, sorry, not a copy-and-paste, just storing a pointer to a passed object in a global ref, just like the String.class is stored.

Sorry.
Can try it. Hang on....

Edit: actually, forget it. I just ran the same test without calling the native code, and the "object address" survived multiple full GCs unchanged, so you need a better methodology for checking whether the address is pinned or not. (I'm assuming that objects are created in Eden and don't stay there through a full GC - unless there have been some major redesigns to the garbage collector I think that's a safe assumption).

Edit2: and the following:
1  
2  
3  
4  
JNIEXPORT jobject JNICALL Java_TestPin_pinStringClass(JNIEnv * env, jclass clazz, jobject foo)
 {
        return (*env)->NewGlobalRef(env, foo);
 }

applied to an object doesn't change the "object address".
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

TehJavaDev (18 views)
2014-08-28 18:26:30

CopyableCougar4 (26 views)
2014-08-22 19:31:30

atombrot (39 views)
2014-08-19 09:29:53

Tekkerue (36 views)
2014-08-16 06:45:27

Tekkerue (33 views)
2014-08-16 06:22:17

Tekkerue (22 views)
2014-08-16 06:20:21

Tekkerue (33 views)
2014-08-16 06:12:11

Rayexar (70 views)
2014-08-11 02:49:23

BurntPizza (46 views)
2014-08-09 21:09:32

BurntPizza (37 views)
2014-08-08 02:01:56
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!