JNI – Cache ID

5/5 - (1 vote)

Khi chúng ta lấy các đối tượng jmethodIDjfieldID thì các đối tượng này sẽ được JNI dò tìm theo phương pháp lookup table, cách này về cơ bản rất tốn thời gian, do đó trong chúng ta có một kỹ thuật gọi là cache ID, chúng ta sẽ tìm hiểu cách cache này.

Về cơ bản thì cache là chúng ta tạo ra một thứ gì đó rồi lưu lại để sử dụng sau này, giống biến static, biến toàn cục, hay constant vậy.

Cache khi khởi tạo

Cache khi khởi tạo tức là chúng ta cache lại ID đó bên code native.

Ví dụ chúng ta có lớp Java như sau:

class Cache { 
    static { System.loadLibrary("Cache"); } 

    private String s = "Hello"; 

    private native void hello(); 

    public static void main(String[] args) {
        Cache c = new Cache();
        c.hello();
    }
}

Bên native sẽ lấy ID của thuộc tính s như sau:

#include "Cache.h"
#include <iostream>

JNIEXPORT void JNICALL Java_Cache_hello (JNIEnv *e, jobject obj) {
    jclass cls = e->GetObjectClass(obj);
    static jfieldID fid_s = NULL;
 
    if(fid_s == NULL) {
        fid_s = e->GetFieldID(cls, "s", "Ljava/lang/String;"); 
    } else {
        std::cout << "s is already got";
    }    
}

Ở đây chúng ta khai báo đối tượng jfieldID là static rồi khởi tạo giá trị NULL, sau đó mỗi lần lấy đối tượng jfieldID từ phương thức GetFieldID() thì trước hết chúng ta kiểm tra xem đối tượng này có phải NULL hay không rồi mới lấy.

Lý do là vì sẽ có trường hợp chúng ta làm multithread mà có tham chiếu đến một ID nhiều lần, mỗi thread tự lookup table để tính ID sẽ chậm hơn nhiều so với việc lưu lại ID đó rồi chỉ cần một thread tính ra để các thread khác sử dụng.

Cache Java

Kiểu cache này là trước khi làm gì thì chúng ta gọi một phương thức để lấy hết các ID ra trước rồi lưu lại để sử dụng sau. Ví dụ:

class Cache {
 
    static { 
        System.loadLibrary("Cache");
        initID(); 
    }
 
    private String s;
    
    private static native void initID();
    private native void hello();
 
    public static void main(String[] args) {
        Cache c = new Cache();
        c.s = "Lorem Ippum";
        c.hello();
    }
}

Ở đây chúng ta có 2 phương thức native là initID()hello().

Phương thức initID() là phương thức static, phương thức này sẽ được gọi trước cả phương thức main(), phương thức này làm công việc lấy các ID ra trước và lưu lại, chúng ta code như sau:

#include "Cache.h"
#include <iostream>
using namespace std;

jfieldID fid_s;

JNIEXPORT void JNICALL Java_Cache_hello (JNIEnv *e, jobject obj) {
    jstring jstr = (jstring)e->GetObjectField(obj, fid_s);
    const char *str = e->GetStringUTFChars(jstr, JNI_FALSE);
    cout << str;
    e->ReleaseStringUTFChars(jstr, NULL);
}

JNIEXPORT void JNICALL Java_Cache_initID (JNIEnv *e, jclass cls) {
    fid_s = e->GetFieldID(cls, "s", "Ljava/lang/String;"); 
}

Như bạn thấy ở phương thức Java_Cache_initID() chúng ta gọi phương thức GetFieldID() và lưu kết quả vào biến fid_s, kể từ đó về sau chúng ta không cần phải gọi lại phương thức này nữa. Phương thức Java_Cache_hello() có thể làm việc với fid_s một cách bình thường.

Lorem Ipsum
5 1 vote
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments