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 :
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");
   ...
}
Maintenant, je regarde les sources de java.net.PlainDatagramSocketImpl en Java, et je veux connaître l'implémentation native de :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
protected synchronized native void receive0(DatagramPacket p) throws IOException;
Je regarde ce qui pourrait correspondre :
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
Je trouve donc jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.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 :
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");
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
/*
 * 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);
Précisément ce qu'il ne faut pas faire, non ?

Qui a raison ? Le tuto ou l'implémentation des bibliothèques standard ?

Merci de votre aide.