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.
Related
using JNI i'm trying to let a C program works under java. Here's the issue.
First i created the java class testcli.java:
public class testcli {
public native void stdErr();
public native int cliFromC();
static {
System.loadLibrary("ctest");
}
public static void main(String[] args) {
new testcli().stdErr();
new testcli().cliFromC();
}
Then compiled with
javac testcli.java
and created header with
javah testcli
after that created the librari ctest.c and compiled with
gcc -o libctest.so -shared -I/path/to/jni.h ctest.c -lc
and i got the libctest.so created, then added to bashrc the following code:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/Desktop/project2/thesys/src
and when i go to type
java testcli
it says me "No such file or directory".
I'm running java 8 oracle on a 32 bit machine with xubuntu 32 bit. Any ideas?
EDIT: ADDED right here the ctest.c code ( i think there might be some errors here)
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <signal.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <netdb.h>
#define PORT 20000
#define LENGTH 512
JNIEXPORT void JNICALL Java_testcli_stdErr
(JNIEnv *env, jobject jobj)
{
const char *msg = NULL;
perror(msg);
exit(1);
}
JNIEXPORT jint JNICALL Java_testcli_cliFromC
(JNIEnv *env, jobject jobj)
{
/* Variable Definition */
int sockfd;
int nsockfd;
char revbuf[LENGTH];
struct sockaddr_in remote_addr;
//struct hostent *server; // per la parte scritta da me
/* Get the Socket file descriptor */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
exit(1);
}
/* Fill the socket address struct */
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(PORT);
/*questo lo faccio così perchè localhost è 127.0.0.1, nel caso in cui debba recuperare l'ip dall'hostname uso la parte commentata sopra*/
inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr); //metto in remote_addr.sin_addr l'indirizzo ip 127.0.0.1 nel formato desiderato
bzero(&(remote_addr.sin_zero), 8);
/* Try to connect the remote */
if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
exit(1);
}
else
printf("[Client] Connected to server at port %d...ok!\n", PORT);
/* Send File to Server */
//if(!fork())
//{
char* fs_name = "/home/elia/Desktop/project/tesi/PublicKey1";
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", fs_name);
FILE *fs = fopen(fs_name, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", fs_name);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", fs_name);
//}
close (sockfd);
printf("[Client] Connection lost.\n");
return (0);
}
Actually, everything is fine. The error comes from your stdErr() function, and it actually shows it is working. I get the same error. Why does this happen?
const char *msg = NULL;
perror(msg);
exit(1);
This prints the last error that was caused in the program. Now, you should only use perror() if you actually had an error in your program. Otherwise, it will print the message of whatever was in the errno variable previously.
errno may have been set by something inside Java itself. It may have been looking for some file, but its non-existence is not a problem for Java so it continued to work. But errno is set to that value and keeps that value, and that's what's printed in your program.
To prove this, I have added the following to your testcli.java:
public native void clearErr();
And my main is:
public static void main(String[] args) {
new testcli().clearErr();
new testcli().stdErr();
new testcli().cliFromC();
}
And to ctest.c I added:
JNIEXPORT void JNICALL Java_testcli_clearErr
(JNIEnv *env, jobject jobj)
{
errno = 0;
}
Did the javac, javah and gcc again, ran the program, and now I get:
Success
Note that your third method is not called because of the exit() in stdErr().
I need to call java method from c program. i have tried below code to call the java method through Java native interface but facing issues while compilation. i m new to C and have experience in java. so, i m not able to think myself what is happening while creating JVM.
Below is the code.
CTest.c
#include <stdio.h>
#include <jni.h>
JNIEnv* create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=D:\\Ashish_Review\\JNI\\src";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
helloWorldClass = (*env)->FindClass(env, "HelloWorld");
mainMethod = (*env)->GetStaticMethodID(env, helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "From-C-program");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, applicationArgs);
}
int main(int argc, char **argv) {
JNIEnv* env = create_vm();
invoke_class( env );
}
C:\Users\Desktop\tcc>tcc C:\TurboC++\Disk\TurboC3\BIN\CTest.c -I "C:\Program Files\Java\jdk1.6.0_16\include" -I "C:\Program Files\Java\jdk1.6.0_16\include\win32" -shared -o CTest.dll
tcc: undefined symbol '_JNI_CreateJavaVM#12'
please help me out.
The error message is about the linking stage, not compilation - you have included the header file, but to create the executable you have to specify the .a (library files) also.
You have to link with JVM's library (add some reference to libjvm.a to the tcc's command line).
If you don't have a precompiled jvm.lib file for TurboC++, there is another option - link with the jvm.dll file and export all the methods from JVM manually. This uses the LoadLibrary/GetProcAddress functions.
For a short sample (sorry, couldn't find the entire export source code), look at this:
/* load library */
HMODULE dll = LoadLibraryA("jvm.dll");
/* declare a function pointer and initialize it with the "pointer" to dll's code */
JNI_CreateJavaVM_func JNI_CreateJavaVM_ptr = GetProcAddress(dll, "JNI_CreateJavaVM");
Later use the JNI_CreateJavaVM_ptr instead of JNI_CreateJavaVM. Also you'll have to declare the JNI_CreateJavaVM_func type - you might just copy the signature from "jni.h"
I'm quite new to JNI and right now I'm using this simple C program to create a JVM and call the main() from my Java project:
#include <stdio.h>
#include <jni.h>
JNIEnv* create_vm() {
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_6;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=CLASSPATH"; //This isn't the actual classhpath, but you get the idea
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
int ret = JNI_CreateJavaVM(&jvm, (void **)&env, &args);
if (ret<0){
printf("\nUnable to Launch JVM");
} else {
printf("\nJVM launched successfully");
}
return env;
}
void invoke_class(JNIEnv* env) {
jclass UncaughtExceptionClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
UncaughtExceptionClass = (*env)->FindClass(env, "exceptioncatcher/ExceptionCatcher");
mainMethod = (*env)->GetStaticMethodID(env, UncaughtExceptionClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "From C");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, UncaughtExceptionClass, mainMethod, applicationArgs);
}
int main(int argc, char **argv) {
JNIEnv* env = create_vm();
invoke_class( env );
}
This works well when running a HelloWorld type java code, but my code actually sets a Default Uncaught Exception Handler. This handler will send the info collected for each uncaught exception to a thread that will process them and send them by email.
Right now these are pretty much all the classes created and it, obviously, won't catch a lot of uncaught exceptions right now. But I use the main() to try it out:
public static void main(String[] args){
Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler());
Integer i = null;
i++;
}
It works fine when I simply run it from netbeans, but the only thing that appears when using the C app is "JVM launched successfully".
Can anyone help on this one?
Managed to make it work in the end (never closed the question before), simply had to build the project and change the classpath to the .jar generated.
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 ?
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!!!");
}