#include <math.h> #include <stdio.h> #include "com_example_conve_stroke_Conve_jni.h" #include "com_example_conve_stroke_Conve_jni_EventListener.h" #include "include/agg_basics.h" #include "include/agg_rendering_buffer.h" #include "include/agg_renderer_base.h" #include "include/agg_renderer_scanline.h" #include "include/agg_rasterizer_scanline_aa.h" #include "include/agg_conv_stroke.h" #include "include/agg_scanline_p.h" #include "include/agg_path_storage.h" #include "include/agg_vcgen_stroke.h" #include "include/agg_vcgen_markers_term.h" #include "include/agg_renderer_scanline.h" #define AGG_RGB565 #include "include/pixel_formats.h" typedef agg::renderer_base<pixfmt> ren_base; typedef agg::renderer_scanline_aa_solid<ren_base> solid_renderer; using namespace agg; typedef struct Color XColor; struct Color { int red; int green; int blue; //int pixel; }; // Pallete XColor pal[256]; // Global env ref (for callbacks) static JavaVM *g_VM; jclass jNativesCls; jmethodID jSendImageMethod; // Java image pixels: int ARGB jintArray jImage; int m_nWidth = 480; int m_nHeight = 320; void jni_send_pixels(int * data, int x, int y, int w, int h) { JNIEnv *env; if ( !g_VM) { return ; } g_VM->AttachCurrentThread (&env, NULL); int iSize = 480 * 320; jImage = env-> NewIntArray(iSize); if (jSendImageMethod) { env->SetIntArrayRegion(jImage, 0, iSize, (jint *) data); // Call Java method env->CallStaticVoidMethod(jNativesCls , jSendImageMethod, jImage , (jint)x, (jint)y, (jint)w, (jint)h); } } void OnDraw() { // 그리기위한 메모리 버퍼 unsigned char *m_pBuffer; rendering_buffer *m_rdBuffer; ren_base *m_rdBase; pixfmt *m_pPixFmt; // m_pBuffer = new unsigned char[m_nWidth * m_nHeight * 2]; m_rdBuffer = new rendering_buffer(); m_rdBuffer->attach(m_pBuffer, m_nWidth, m_nHeight, m_nWidth * 2); m_pPixFmt = new pixfmt(*m_rdBuffer); m_rdBase = new ren_base(*m_pPixFmt); // m_rdBase->clear(rgba(1, 1, 1)); rasterizer_scanline_aa<> ras; scanline_p8 sl; solid_renderer solid(*m_rdBase); path_storage path; path.move_to(50, 50); path.line_to(400, 150); path.line_to(50, 250); line_cap_e cap = butt_cap; line_join_e join = miter_join; // (1) conv_stroke<path_storage> stroke(path); stroke.line_join(join); stroke.line_cap(cap); stroke.miter_limit(4); stroke.width(20); ras.add_path(stroke); render_scanlines_aa_solid(ras, sl, *m_rdBase, rgba(0, 0, 0)); // (1) int size = m_nWidth * m_nHeight; // ARGB pixels int pixels[size], i; unsigned char rgb[3]; for ( i = 0 ; i < size ; i ++) { rgb[0] = m_pBuffer[i*2] & 0xF8; // r rgb[1] = (m_pBuffer[i*2] & 0x07) | ((m_pBuffer[i*2+1] & 0xE0) >> 3); // g rgb[2] = m_pBuffer[i*2+1] & 0x1F; // b pixels[i] = 0xFF000000 | (rgb[2] << 16) | (rgb[1] << 8) | (rgb[0]); } jni_send_pixels(pixels,0,0, m_nWidth, m_nHeight); } int agg_main() { JNIEnv *env; if ( !g_VM) { return 0; } g_VM->AttachCurrentThread (&env, NULL); // call OnInitGraphics(w, h); jmethodID mid = env->GetStaticMethodID(jNativesCls , "OnInitGraphics" , "(II)V"); if (mid) {env->CallStaticVoidMethod(jNativesCls , mid , m_nWidth, m_nHeight); } OnDraw(); //g_pMD = new CDrawMD(); //g_pMD->FireThread(); return 1; } JNIEXPORT jint JNICALL Java_com_example_conve_1stroke_Conve_1jni_agg_1mainJNI (JNIEnv * env, jclass cls) { env->GetJavaVM(&g_VM); jNativesCls = env->FindClass("com/example/conve_stroke/Conve_jni"); if ( jNativesCls == 0 ) { printf("Unable to find class: com/example/conve_stroke/Conve_jni"); return -1; } // Load doom.util.Natives.OnImageUpdate(char[]) jSendImageMethod = env->GetStaticMethodID(jNativesCls , "OnImageUpdate" , "([IIIII)V"); if ( jSendImageMethod == 0 ) { jni_printf("Unable to find method OnImageUpdate(byte[])"); return -1; } return agg_main(); }
Wolf3D를 참고하여 만든 소스입니다.
그래픽은 agg를 사용했고 V자를 그립니다.
java쪽에서 jni를 호출하여 잘 그려지는 소스입니다.
근데 116번 라인을 117번,118번으로 바꾸고 OnDraw()함수도 CDrawMD클래스에 넣어서
쓰레드로 jni_send_pixels()함수를 호출하면 52번라인에서 Java method 를 호출하지 못합니다
JNI WARNING : 0x4300000 is not a valid JNI reference 라고 뜨는데 인터넷에 뒤져보면
Local references and memory leaks
The automatic garbage collection of local references that are no longer in scope prevents memory leaks in most situations. This automatic garbage collection occurs when a native thread returns to Java (native methods) or detaches from the JVM (Invocation API). Local reference memory leaks are possible if automatic garbage collection does not occur. A memory leak might occur if a native method does not return to the JVM, or if a program that uses the Invocation API does not detach from the JVM.
Consider the code in the following example, where native code creates new local references in a loop:
while ( <condition> ) { jobject myObj = (*env)->NewObject( env, clz, mid, NULL ); if ( NULL != myObj ) { /* we know myObj is a valid local ref, so use it */ jclass myClazz = (*env)->GetObjectClass(env, myObj); /* uses of myObj and myClazz, etc. but no new local refs */ /* Without the following calls, we would leak */ (*env)->DeleteLocalRef( env, myObj ); (*env)->DeleteLocalRef( env, myClazz ); } } /* end while */
Although new local references overwrite the myObj and myClazz variables inside the loop, every local reference is kept in the root set. These references must be explicitly removed by the DeleteLocalRef call. Without the DeleteLocalRef calls, the local references are leaked until the thread returned to Java or detached from the JVM.
이것이 해결책 인것 같기도한데 해결이 안됩니다.
그리고 JNI_CreateJavaVM 이라고 있던데 이걸 사용 해야 되는건지 GetJavaVM 와는 어떻게 다른건지
아시는분 시원하게 답좀 해주세요.
static jclass jGlobalCls;
JNIEXPORT jint JNICALL Java_com_endcs_Wavi_WaviJni_agg_1mainJNI(JNIEnv * env, jclass cls)
{
jclass jNativesCls = env->FindClass("com/endcs/Wavi/WaviJni");
/* Create a global reference */
jGlobalCls = (jclass)env->NewGlobalRef(jNativesCls);
/* The local reference is no longer useful */
env->DeleteLocalRef(jNativesCls);
}
아무도 답변이 없네요
NDK쓰레드 쓰시는 분의 발전을 위해서 고수분의 답변을 공개 하겠습니다.
자바는 쓰레드가 되었던 뭐가 되었던 메모리 관리를 가상 머신이 알아서 해 줍니다.
그러니 레퍼런스를 잃어버린 메모리는 알아서 가비지 처리가 된다는 거죠..
그런데 문제는 C++은 가비지 콜렉터 같은 것이 존재하지 않습니다.
그러므로 지역변수로 사용하려고 하면 문제가 발생할 수 있구요..
이때는 반드시 메모리를 삭제하는 프로세스를 태워야 합니다.
아니면 메모리를 유지 관리할 수 있도록 다른 곳에 레퍼런스를 넘겨야 하는데 이게 문제가 됩니다.
지역 변수의 특성상 스코프를 넘어가게 되면 메모리에서 레퍼런스를 잃어버리게 되기 때문에
지역변수로 생성된 메모리는 결국 지역 변수 범위 내에서 파괴해야 된다는 거져..
변수의 스코프 조정을 하면 어느 정도는 해결이 될듯 싶습니다.