Dans ce tuto sur JNI (et dans bien d'autres), il est écrit clairement qu'on ne doit pas garder une référence locale pour une réutilisation future :
Maintenant, je regarde les sources de java.net.PlainDatagramSocketImpl en Java, et je veux connaître l'implémentation native de :By default, JNI creates local references to ensure that they are liable for garbage collection. Because of this, you may unintentionally write illegal code by trying to store away a local reference so that you can reuse it later, as shown in the code sample below:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 /* This code is invalid! */ static jmethodID mid; JNIEXPORT jstring JNICALL Java_Sample1_accessMethod(JNIEnv *env, jobject obj) { ... cls = (*env)->GetObjectClass(env, obj); if (cls != 0) mid = (*env)->GetStaticMethodID(env, cls, "addInt", "(I)I"); ... }
Je regarde ce qui pourrait correspondre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part protected synchronized native void receive0(DatagramPacket p) throws IOException;
Je trouve donc jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 $ grep -rl receive0 | grep '\.c$' jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c jdk/src/windows/native/sun/nio/ch/DatagramChannelImpl.c jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c jdk/src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
Dedans, il y a plein de jfieldID en tant que variables externes static. Par exemple :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 static jfieldID IO_fd_fdID; static jfieldID pdsi_fdID; static jfieldID pdsi_timeoutID; static jfieldID pdsi_trafficClassID; static jfieldID pdsi_localPortID; static jfieldID pdsi_connected; static jfieldID pdsi_connectedAddress; static jfieldID pdsi_connectedPort;
Le début de l'implémentation du constructeur :
Et voici le début de l'implémentation de la méthode receive0 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 /* * Class: java_net_PlainDatagramSocketImpl * Method: init * Signature: ()V */ JNIEXPORT void JNICALL Java_java_net_PlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) { #ifdef __linux__ struct utsname sysinfo; #endif char *s; pdsi_fdID = (*env)->GetFieldID(env, cls, "fd", "Ljava/io/FileDescriptor;"); CHECK_NULL(pdsi_fdID); pdsi_timeoutID = (*env)->GetFieldID(env, cls, "timeout", "I");
Précisément ce qu'il ne faut pas faire, non ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 /* * Class: java_net_PlainDatagramSocketImpl * Method: receive * Signature: (Ljava/net/DatagramPacket;)V */ JNIEXPORT void JNICALL Java_java_net_PlainDatagramSocketImpl_receive0(JNIEnv *env, jobject this, jobject packet) { char BUF[MAX_BUFFER_LEN]; char *fullPacket = NULL; int mallocedPacket = JNI_FALSE; jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); jint timeout = (*env)->GetIntField(env, this, pdsi_timeoutID);
Qui a raison ? Le tuto ou l'implémentation des bibliothèques standard ?
Merci de votre aide.
Partager