Can anybody explain to me why can I get a callback when jvm allocates some java objects, but not others? Here is what I am doing:
static jvmtiCapabilities capa;
static jvmtiEnv* jvmti = NULL;
static const char* fileName = "C:\\temp\\ObjectInitCallbackDump.txt";
static ofstream outFileStream;
void JNICALL callbackObjectAllocation ( jvmtiEnv* jvmti_env,
JNIEnv* jni_env,
jthread thread,
jobject object,
jclass object_klass,
jlong size )
{
char* generic_ptr_class;
char* class_name;
jvmtiError error;
error = jvmti_env->GetClassSignature(object_klass, &class_name, &generic_ptr_class);
if (check_jvmti_error(jvmti_env, error, "Failed to get class signature")) {
return;
}
outFileStream << class_name << std::endl;
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
jint result;
jvmtiError error;
jvmtiEventCallbacks callbacks;
outFileStream.open(fileName,ios::trunc);
result = jvm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_1);
if (result != JNI_OK || jvmti == NULL) {
printf("error\n");
return JNI_ERR;
} else {
printf("loaded agent\n");
}
(void) memset(&capa, 0, sizeof(jvmtiCapabilities));
capa.can_generate_vm_object_alloc_events = 1;
error = jvmti->AddCapabilities(&capa);
if (check_jvmti_error(jvmti, error, "Unable to set capabilities") != JNI_OK) {
return JNI_ERR;
}
(void) memset(&callbacks, 0, sizeof(callbacks));
callbacks.VMObjectAlloc = &callbackObjectAllocation;
error = jvmti->SetEventCallbacks(&callbacks, (jint) sizeof(callbacks));
if (check_jvmti_error(jvmti, error, "Unable to set callbacks") != JNI_OK) {
return JNI_ERR;
}
error = jvmti->SetEventNotificationMode( JVMTI_ENABLE,
JVMTI_EVENT_VM_OBJECT_ALLOC,
(jthread) NULL);
if (check_jvmti_error(jvmti, error,
"Unable to set method entry notifications") != JNI_OK) {
return JNI_ERR;
}
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
outFileStream.close();
}
When I examine the file that I create, I do not see the classes that I am interested in, although I know they are there and NetBeans tells me there is exactly one instance of that class in the jvm. Any thoughts???
Nikita
For performance reasons, the JVMTI only supports allocation events for objects that cannot be detected through bytecode instrumentation (BCI), as explained in the JVMTI VMObjectAlloc event documentation. This means that the event will not be triggered for most object allocations. I assume that the allocations you are missing fall within that category.
Fortunately, it's not really too difficult to intercept all object allocations using BCI. The HeapTracker demo illustrates precisely how to intercept all object allocations in a JVMTI agent using java_crw_demo in addition to the VMObjectAlloc events.
Maybe you are just not hitting your check?
If this is the code you actually run then you have a bug; you missed the ; at the end of the object
Your compare should be like this:
if (strcmp(class_name,"Ljavax/swing/JFrame;") == 0) {
printf("Got the sucker!!!");
}
Related
I use -XX:+PrintNMTStatistics to get Memory Status.
but it can't be store in file
so how can i save those info to a file ?
-XX:+PrintNMTStatistics prints to JVM console, and this can't be changed.
However, it is possible to create your own utility that will dump NMT statistics to a file before JVM exits.
The idea is similar to this answer: create a JVMTI agent that intercepts VMDeath event and then uses JVM Management Interface to call VM.native_memory diagnostic command.
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
static const char* filename;
extern void* JNICALL JVM_GetManagement(jint version);
static void* get_management_func() {
void** jmm;
if ((jmm = JVM_GetManagement(0x20010000)) != NULL) return jmm[39];
if ((jmm = JVM_GetManagement(0x20020000)) != NULL) return jmm[37];
if ((jmm = JVM_GetManagement(0x20030000)) != NULL) return jmm[38];
return NULL;
}
static void save_to_file(const char* result_str) {
FILE* f = fopen(filename, "w");
if (f != NULL) {
fprintf(f, "%s", result_str);
fclose(f);
} else {
fprintf(stderr, "%s", result_str);
}
}
void JNICALL VMDeath(jvmtiEnv* jvmti, JNIEnv* env) {
jstring (JNICALL *func)(JNIEnv*, jstring) = get_management_func();
if (func == NULL) {
fprintf(stderr, "JMM interface is not supported on this JVM\n");
return;
}
jstring cmd = (*env)->NewStringUTF(env, "VM.native_memory summary");
jstring result = func(env, cmd);
if (result != NULL) {
const char* result_str = (*env)->GetStringUTFChars(env, result, NULL);
save_to_file(result_str);
(*env)->ReleaseStringUTFChars(env, result, result_str);
}
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
filename = options != NULL ? strdup(options) : "";
jvmtiEnv* jvmti;
(*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_0);
jvmtiEventCallbacks callbacks = {0};
callbacks.VMDeath = VMDeath;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
return 0;
}
Save the above code to nmtdump.c and compile it:
gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -shared -fPIC -olibnmtdump.so nmtdump.c
Then run Java with our agent:
java -XX:NativeMemoryTracking=summary -agentpath:/path/to/libnmtdump.so=dump.txt ...
Now, when JVM exits, it will save NMT report to dump.txt.
I am using the Android NDK on a Motorola G6, running Android 8.0.
I am using JNI to perform periodic callbacks to my Java code in the following:
if ( data_arg && g_vm && g_obj ) {
jint res = (*g_vm)->GetEnv(g_vm, (void**)&g_env, JNI_VERSION_1_6);
if (res != JNI_OK) {
res = (*g_vm)->AttachCurrentThread(g_vm, &g_env, NULL);
if (JNI_OK != res) {
return NULL;
}
jclass interfaceClass = (*g_env)->GetObjectClass(g_env,g_obj);
if (!interfaceClass) {
return NULL;
}
g_mid = (*g_env)->GetMethodID(g_env,interfaceClass, "readCallback", "(I[B)V");
if (!g_mid){
return NULL;
}
jbyteArray dataByteArray = (*g_env) -> NewByteArray(g_env,data_arg->len);
(*g_env)->SetByteArrayRegion(g_env, dataByteArray, 0,data_arg->len,(jbyte*)data_arg->data);
(*g_env)->CallVoidMethod(g_env, g_obj,(jmethodID)g_mid, (jint)data_arg->len, (jbyteArray)dataByteArray);
(*g_env)->DeleteLocalRef(g_env,dataByteArray);
(*g_env)->DeleteLocalRef(g_env,res);
(*g_env)->DeleteLocalRef(g_env,interfaceClass);
}
The g_vm and g_obj variables are initialized when the app starts up with the following:
JNIEXPORT jint JNICALL Java_com_abc_register(JNIEnv *env, jobject obj) {
int returnValueBool = 1;
(*env)->GetJavaVM(env, &g_vm);
g_obj = (*env)->NewGlobalRef(env,obj);
g_env = env;
g_res = JNI_ERR;
return (jint)returnValueBool;
}
The class that calls the above register method is a static instance.
The callbacks occur about about 20 Hz. The callbacks are called from a single thread, which is why the DetachCurrentThread method is not called. The app typically runs ok for a few minutes, until it crashes.
The crash produces the following stack trace:
* thread #65, name = 'JVMTI Agent thr', stop reason = signal SIGSEGV: invalid address (fault address: 0x765630)
* frame #0: 0x92b8d44e libopenjdkjvmti.so`openjdkjvmti::MethodUtil::GetMethodName(_jvmtiEnv*, _jmethodID*, char**, char**, char**) + 410
Before the crash occurs, memory and cpu usage are not excessive, nor is the thread count too high. I do not believe there is a memory leak based on the android profiler view
shown here
Thanks a ton in advance!
I'm trying to get access to pdf files in my app using https://github.com/barteksc/PdfiumAndroid
and adding some functions like searching and highlighting using java and c++. the problem is that I always get a crash with no exception details. In debugging I found SIGABRT (signal SIGABRT) SIG:9 fault address
debug info
My native function is
#include <fpdftext.h>
JNIEXPORT jstring JNICALL Java_[my package]_PdfiumCore_nativeGetPageText(JNIEnv *env, jobject instance, jlong pagePtr) {
unsigned short* buffer;
FPDF_TEXTPAGE text_page = FPDFText_LoadPage((FPDF_PAGE) pagePtr);
int len = FPDFText_CountChars(text_page);
FPDFText_GetText(text_page,0,len,buffer);
jstring txt = env->NewString(buffer, len);
FPDFText_ClosePage(text_page);
return txt; }
java function in PdfiumCore.java
public String getPageText(PdfDocument doc, int pageIndex)
{
String txt;
synchronized (lock) {
try {
txt = nativeGetPageText(openPage(doc,pageIndex));
return txt;
}catch (Exception e)
{
Log.e("Error ",e.getMessage());
return "";
}
}
}
public long openPage(PdfDocument doc, int pageIndex) {
long pagePtr;
synchronized (lock) {
pagePtr = nativeLoadPage(doc.mNativeDocPtr, pageIndex);
doc.mNativePagesPtr.put(pageIndex, pagePtr);
return pagePtr;
}
}
function call
Log.e("Page 0",pdfiumCore.getPageText(pdfDocument,0));
The function retrieves the data once then the app crashes. I guess the problem is when the garbage collector tries to delete the buffer pointer which is used in FPDFText_GetText function. but I don't know how to solve it.
any suggestion please.
I solved the problem by deleting the pointer after getting the data by using this code in the JNI function
JNIEXPORT jstring JNICALL Java_[my package]_PdfiumCore_nativeGetPageText(JNIEnv *env, jobject instance,
jlong pagePtr) {
jstring txt;
FPDF_TEXTPAGE text_page = FPDFText_LoadPage((FPDF_PAGE) pagePtr);
int len = FPDFText_CountChars(text_page);
unsigned short *buffer = new unsigned short[len];
FPDFText_GetText(text_page, 0, len, buffer);
txt = env->NewString(buffer,len);
delete[](buffer);
FPDFText_ClosePage(text_page);
return txt;}
I have requirement to integrate spring with some native code written C and I am new to spring and don't have any idea about it if anybody have experience to integrate spring with JNI then please share with me.
Thanks in advance.
The question is quite vague but I can offer a couple of bits of advice from work I've done in the past.
Forget about integrating with "Spring". Concentrate on integrating with Java and let Spring help you out later.
Be very, very careful with the types and memory allocation in C
Here's a book on JNI that I found immensely helpful when I was working on it. It's a little dated but still valid
I did most of the work in C and then patched in a simple single method hook to Java. That way I did most of the integration with the existing code in its native language.
Give your C code a main method that lets you test the C code independently of the Java. Then you can compile your C file as both a library (dll/so) and an executable. The executable can be called on it's own with arguments to test the calls to existing calls.
The general process is.
Java End
public class statusBlock {
/* A Java representation of a Status Block */
private long errcode = 0;
private long errref = 0;
private String errmsg = "";
private long[] TmidArray;
private long evt_id = 0;
private short IgViolation_severity = 0;
}
public class MyFunkyJNIClass {
private Object response;
/**
* To generate the C-header for a native call use: javah -jni
* example.package.MyFunkyJNIClass from target/classes folder.
*/
private native int nativeExecuteFunction(int callType, Object payload, Object response);
public MyFunkyJNIClass() {
System.loadLibrary("theCLibrary");
}
}
In the example above I load the C side of the code using System.loadLibrary and define some fields that I can populate from my C code. To execute just call the native function nativeExecuteFunction(1, "my payload", respObject); On the C side I can use the first argument to choose what to do. It simplified my problems at the time
C Side
JNIEXPORT jint JNICALL Java_example_package_MyFunkyJNIClass_nativeExecuteFunction(JNIEnv *env, jobject this, jint CallType, jobject Payload)
{
// **** JNI Specific declarations for mapping ****
jclass cls, cls2, cls3;
jmethodID mid, mid2;
jfieldID fid;
jint rc = 0;
jsize js = 0;
jbyte jb;
jobject jobj, jobj2, jro;
jobjectArray jobjArray, jobjArray2;
_svc_results results;
switch ((int)CallType)
{
case CALLTYPE1: // 1
DEBUG_PRINT("JNI Call Type 1 in progress...\n");
// JNI mapping happens here
stat = DoSomethingInC(args, &results);
// Map from C structure (_statblk) to Java object
if (stat == SUCCESS) {
DEBUG_PRINT("\tMapping from C structure (_statblk) to Java object\n");
cls = (*env)->FindClass(env, "Lexample/package/statusBlock;");
mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); if (mid == NULL) return -1;
jro = (*env)->NewObject(env, cls, mid); if (jro == NULL) return -1;
fid = (*env)->GetFieldID(env, cls, "errcode","I"); if (fid == NULL) return -1;
(*env)->SetIntField(env, jro, fid, (jint)results.statblk.errcode);
DEBUG_PRINT("\t\tMapped errcode: %d\n",results.statblk.errcode);
fid = (*env)->GetFieldID(env, cls, "errref","I"); if (fid == NULL) return -1;
(*env)->SetIntField(env, jro, fid, (jint)results.statblk.errref);
DEBUG_PRINT("\t\tMapped errref: %d\n",results.statblk.errref);
fid = (*env)->GetFieldID(env, cls, "errmsg","[B"); if (fid == NULL) return -1;
jobj = (*env)->NewByteArray(env, MAX_ERR);
(*env)->SetByteArrayRegion(env, (jbyteArray)jobj, 0, MAX_ERR, (jbyte*)results.statblk.errmsg);
(*env)->SetObjectField(env, jro, fid, jobj);
(*env)->DeleteLocalRef(env, jobj);
DEBUG_PRINT("\t\tMapped errmsg: %s\n",results.statblk.errmsg);
fid = (*env)->GetFieldID(env, cls, "TmidArray","[I"); if (fid == NULL) return -1;
jobj = (*env)->NewIntArray(env, (jsize)results.statblk.TmidArray.TmidArray_len);
(*env)->SetIntArrayRegion(env, (jintArray)jobj, 0,
(jsize)results.statblk.TmidArray.TmidArray_len,
(jint*)results.statblk.TmidArray.TmidArray_val);
(*env)->SetObjectField(env, jro, fid, jobj);
(*env)->DeleteLocalRef(env, jobj);
DEBUG_PRINT("\t\tMapped TmidArray\n");
fid = (*env)->GetFieldID(env, cls, "evt_id","I"); if (fid == NULL) return -1;
(*env)->SetIntField(env, jro, fid, (jint)results.statblk.evt_id);
DEBUG_PRINT("\t\tMapped evt_id: %d\n",results.statblk.evt_id);
cls = (*env)->GetObjectClass(env, this);
fid = (*env)->GetFieldID(env, cls, "response","Ljava/lang/Object;"); if (fid == NULL) return -1;
(*env)->SetObjectField(env, this, fid, jro);
DEBUG_PRINT("\tMapping from C structure (_statblk) to Java object - DONE\n");
} else {
DEBUG_PRINT("JNI Call Type 1 in progress... Returning Error: %d\n", stat);
return (jint)stat;
}
/* Free our native memory */
cls = (*env)->GetObjectClass(env, Payload);
fid = (*env)->GetFieldID(env, cls, "message","Ljava/lang/String;"); if (fid == NULL) return -1;
jobj = (*env)->GetObjectField(env, Payload, fid);
GPS_Free(results.statblk.TmidArray.TmidArray_val);
GPS_Free(results.statblk.ErrorArray.ErrorArray_val);
DEBUG_PRINT("JNI RTP Posting in progress... DONE\n");
break;
case PING: // 2
DEBUG_PRINT("No Java to C mapping required\n");
DEBUG_PRINT("JNI Ping in progress...\n");
stat = doPing();
DEBUG_PRINT("No C to Java mapping required\n");
// Stop null pointer exception if client tries to access the response object.
cls = (*env)->FindClass(env, "Lexample/package/EmptySerializableClass;");
mid = (*env)->GetMethodID(env, cls, "<init>", "()V"); if (mid == NULL) return -1;
jro = (*env)->NewObject(env, cls, mid); if (jro == NULL) return -1;
cls = (*env)->GetObjectClass(env, this);
fid = (*env)->GetFieldID(env, cls, "response","Ljava/lang/Object;"); if (fid == NULL) return -1;
(*env)->SetObjectField(env, this, fid, jro);
DEBUG_PRINT("JNI Ping in progress... DONE\n");
return (jint)rpc_stat;
break;
default:
fprintf(stderr,"Unknown call type\n");
rc = -1;
break;
}
return rc;
}
I could go on and on, but it just takes a bit of careful reading of that book.
There doesn't really need to be any further integration with Spring. You could stick a #Component or #Service annotation on the MyFunkyJNIClass.
I hope this is of some help to you.
Echoing previous answers that Spring Integration is not really the important thing here. More importantly, is having the JVM interface to your native C/C++ node. Since the question was asked there are a number of online resources available that should help new users to this space.
JNI Integration walktrough
The Java™ Native Interface: Programmer’s Guide and Specification book is also quite useful
If you really want to go deep then the official specification is very helpful
When i run the following :
#include<stdio.h>
#include"Package_HelloWorld.h"
#include"Package_Prompt.h"
jstring Java_Package_Prompt_getLine
(JNIEnv *env, jobject obj,jstring prompt) {
char buf[128];
const jbyte *str;
str = (*env)->GetStringUTFChars(env,prompt,NULL);
if(str == NULL) {
return NULL;
}
printf("%s",str);
(*env)->ReleaseStringUTFChars(env,prompt,str);
scanf("%s",buf);
return (*env)->NewStringUTF(env,buf);
}
to generate the dll file i get the following errors.
My IDE is Code:Blocks. What is the reason i get these errors ?