将本机指针存储在Java对象中的"正确"方法是什么?
我可以将指针视为Java int,如果我碰巧知道本机指针的大小是<= 32位,或者long如果我碰巧知道本机指针的大小是<= 64位的话.但有没有更好或更清洁的方法来做到这一点?
编辑:从JNI函数返回一个指针原生到底是什么我也不想做.我宁愿返回一个代表本机资源的Java对象.但是,我返回的Java对象必须有一个包含指针的字段,这使我回到原始问题.
或者,是否有一些更好的方法让JNI函数返回对本机资源的引用?
我正在尝试使用别人的Makefile来编译一个非常简单的c ++库.makefile如下:
JNIFLAGS=-O2 -pthread -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux
all:
rm -f ../dist/libUtils.so
g++ $(JNIFLAGS) -c -m32 -o com_markets_utils_dates_NativeTime.o com_markets_utils_dates_NativeTime.cpp
g++ $(JNIFLAGS) -c -m32 -o DateUtil.o DateUtil.cpp
g++ -pthread -m32 -shared -fPIC -o ../dist/libUtils.so DateUtil.cpp
g++ -pthread -m32 -shared -fPIC -o ../dist/libNativeTime.so DateUtil.o com_markets_utils_dates_NativeTime.o
Run Code Online (Sandbox Code Playgroud)
这编译很好,但链接器抱怨:
...
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.1/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.1/libstdc++.a when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.1/libstdc++.so when searching for -lstdc++
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/4.4.1/libstdc++.a when searching for -lstdc++
/usr/bin/ld: cannot find -lstdc++
collect2: …Run Code Online (Sandbox Code Playgroud) 我有一个Eclipse插件(A),它依赖于另一个插件(B).插件B只是一个jar包装器,它包含一个本机dll,并执行jni功能.鉴于此设置,我在A的Activator类的start方法中有以下代码:
MessageConsole jniConsole = new MessageConsole("Opereffa Output", null);
ConsolePlugin.getDefault().getConsoleManager().addConsoles(new IConsole[] { jniConsole });
ConsolePlugin.getDefault().getConsoleManager().showConsoleView(jniConsole);
MessageConsoleStream stream = jniConsole.newMessageStream();
System.setOut(new PrintStream(stream));
System.setErr(new PrintStream(stream));
Run Code Online (Sandbox Code Playgroud)
当插件A执行其功能时,System.out的任何使用实际上都会进入Eclipse中的控制台.但是JNI使用的本机代码也会写入输出流,这是我无法抓取的.在开发期间,JNI的输出转到Eclipse实例的控制台,该实例已启动包含插件的运行实例.
那么如何获取JNI输出并在控制台中显示?
假设我将Sun的JVM嵌入到C++应用程序中.通过JNI,我调用了一个Java方法(我自己的),它又调用了我在共享库中实现的本机方法.
如果此本机方法抛出C++异常会发生什么?
编辑:编译器是gcc 3.4.x,jvm是sun的1.6.20.
我自己和一些队友一直无法理解为什么下面的代码片段在使用JVM版本1.6u23到1.6u31(本帖子的最新版本)时不能提供正确的输出.此代码段代表了一个更大问题的简化:
更新:稍微修改了示例,重点关注"virtual_function()"似乎没有被调用的问题.
更新:根据迄今为止的评论更简化示例.
NodeTester.cpp:
#include <iostream>
#include <jni.h>
class Node {
public:
Node () :m_counter(0) {}
virtual ~Node () {}
virtual void virtual_function () {
m_counter += 10;
}
void non_virtual_function () {
m_counter += 1;
}
int get_counter () {
return m_counter;
}
private:
int m_counter;
};
extern "C" {
JNIEXPORT void JNICALL Java_NodeTester_testNode (JNIEnv *jni_env_rptr,
jclass java_class) {
Node *node_rptr = new Node();
node_rptr->non_virtual_function();
node_rptr->virtual_function();
std::cout << node_rptr->get_counter() << std::endl;
delete node_rptr;
}
}
Run Code Online (Sandbox Code Playgroud)
NodeTester.java:
public class NodeTester …Run Code Online (Sandbox Code Playgroud) 10月25日更新:
现在我发现了导致问题的原因.
1)子进程自杀,这就是strace/perf/auditctl无法跟踪它的原因.
2)从Java线程触发创建进程的JNI调用.当线程最终死亡时,它也会破坏它创建的进程.
3)在我的代码fork和execve()子进程中,我有代码来监视父进程死亡并使用以下行终止我的子进程:prctl(PR_SET_PDEATHSIG,SIGKILL); 我的错,我没有特别注意这个标志在b/c之前它被认为是我的其他项目的最佳实践,其中子进程从主线程分叉.
4)如果我注释掉这一行,问题就消失了.最初的目的是在父进程消失时终止子进程.即使没有这个标志,它仍然是正确的行为.好像是ubuntu框的默认行为.
5)最后发现它是一个内核bug,在内核版本3.4.0中修复,我在AWS上的ubuntu框是内核版本3.13.0-29-generic.
这些问题有几个有用的链接:
a)http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them
b)在父线程退出时调用prctl(PR_SET_PDEATHSIG,SIGNAL),而不是父进程退出.
c)https://bugzilla.kernel.org/show_bug.cgi?id=43300
10月15日更新:
非常感谢所有的建议.我正在调查系统的一个区域到另一个区域.很难找到理由.
我想知道两件事.1)为什么像strace,auditctl和perf脚本这样强大的工具无法追踪导致杀戮的人?
2)被SIGKILL +++杀死的+++真的意味着它被信号杀死了吗?
原始邮政
我从Ubuntu 12中的Java应用程序服务器通过JNI接口启动了一个长时间运行的C进程.我使用JNI接口来启动进程而不是通过Java的进程构建器的原因是b/c的性能原因.对于java进程构建器来说,使用IPC非常低效,特别是b/c额外的缓冲引入了很长的延迟.
它会定期被SIGKILL神秘地终止.我发现的方式是通过strace,它说:"+++被SIGKILL +++杀死"
我检查了以下内容:
我被它终止的原因感到困惑.有没有人有一个很好的建议如何追踪它?
PS
在我的ubuntu限制 - 结果是:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7862
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files …Run Code Online (Sandbox Code Playgroud)我正在开发一个Android项目,该项目使用一个Java类库作为包装器C++.C++库是一个公司内部库,我们可以访问它的源代码,但在Android项目中它只是动态链接的,所以它只能以头文件(.h)和共享对象(.so)的形式使用.有权访问库源代码,是否可以向Android Studio指定源代码的路径,以便我可以使用调试器进入库内部?
调试器工作,我可以进入Java_clory_engine_sdk_CloryNative_nativeInit函数内部,但我还想进一步调试对应于Clory::Engine该类的库,正如我所提到的,它是一个我们有源代码访问的内部库.
例如,Clory::Engine::instance是库的一部分,我想向Android Studio指定CloryEngine.cpp文件的位置,以便我可以Clory::Engine::instance使用调试器进入内部,从而调试此静态成员函数.
我使用的是Android Studio 3.1.4.
这可能吗?
编辑:
该clory-sdk.gradle文件指定CMakeLists.txt配置C++层的文件.
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
Run Code Online (Sandbox Code Playgroud)
所以我使用的是使用Clory SDK的内部应用程序.在app.gradle我使用的文件内:
dependencies {
...
compile project(':clory-sdk-core')
compile project(':clory-sdk')
...
}
Run Code Online (Sandbox Code Playgroud)
所以我不认为我们在项目中使用aars app.gradle.该aars的运到客户端,但我们使用app.gradle的项目在这之前测试我们的小SDK功能.JNI层位于clory-sdk-core项目内部.
编辑2:
这是CMakeLists.txt处理JNI层的:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_BUILD_TYPE …Run Code Online (Sandbox Code Playgroud) c++ java-native-interface android android-studio android-studio-3.0
我在Android上运行C++代码库,并希望用户发送崩溃报告.
我正在使用ACRA库,它可以很好地用于Java代码,但是当本机代码崩溃时,我得不到足够的信息.实际上我想收到本机函数调用的堆栈跟踪.我知道在我的进程结束后会将崩溃信息打印到logcat中,我可以配置ACRA来读取/发送logcat.我已经设置了我的代码,使用信号处理程序检测本机崩溃,并回调Java以便ACRA报告.它也很好用.
然而,这种方法的时机不合适 - ACRA在崩溃进程仍然存活时读取日志,并且在崩溃进程完全结束后,Android(不确切知道哪个部分)将崩溃报告写入logcat.所以我在使用ACRA时没有收到堆栈跟踪.
所以我正在寻找一种以编程方式从C++代码中读取当前堆栈跟踪的方法,并将此信息提供给ACRA(或者其他崩溃报告工具).
我只需要写一些写入logcat的报告:
10-10 08:29:13.868: INFO/DEBUG(1121): #00 pc 0003fc7c /data/data/com.ex.lib/libapp.so
10-10 08:29:13.891: INFO/DEBUG(1121): #04 pc 00016df4 /system/lib/libdvm.so
10-10 08:29:13.891: INFO/DEBUG(1121): #05 pc 00045284 /system/lib/libdvm.so
10-10 08:29:13.899: INFO/DEBUG(1121): #15 pc 00047c56 /system/lib/libdvm.so
10-10 08:29:13.922: INFO/DEBUG(1121): #16 pc 00030e4c /system/lib/libandroid_runtime.so
Run Code Online (Sandbox Code Playgroud)
有没有办法从我的代码中获取这个堆栈跟踪?
我有一个java对象,它通过JNI调用C++共享对象.在C++中,我保存了对JNIEnv和jObject的引用.
JavaVM * jvm;
JNIEnv * myEnv;
jobject myobj;
JNIEXPORT void JNICALL Java_org_api_init
(JNIEnv *env, jobject jObj) {
myEnv = env;
myobj = jObj;
}
Run Code Online (Sandbox Code Playgroud)
我还有一个GLSurface渲染器,它最终在另一个线程GLThread上调用上面提到的C++共享对象.然后我尝试使用我最初保存的jobject回调到我的原始Java对象,但我想因为我在GLThread上,我得到以下错误.
W/dalvikvm(16101): JNI WARNING: 0x41ded218 is not a valid JNI reference
I/dalvikvm(16101): "GLThread 981" prio=5 tid=15 RUNNABLE
I/dalvikvm(16101): | group="main" sCount=0 dsCount=0 obj=0x41d6e220 self=0x5cb11078
I/dalvikvm(16101): | sysTid=16133 nice=0 sched=0/0 cgrp=apps handle=1555429136
I/dalvikvm(16101): | schedstat=( 0 0 0 ) utm=42 stm=32 core=1
Run Code Online (Sandbox Code Playgroud)
回调Java的代码:
void setData()
{
jvm->AttachCurrentThread(&myEnv, 0);
jclass javaClass = myEnv->FindClass("com/myapp/myClass");
if(javaClass == …Run Code Online (Sandbox Code Playgroud) 我和一个朋友一起创建了一个Android应用来组织学校成绩。该应用程序可以在我的设备和大多数用户设备上正常运行,但是崩溃率超过3%,这主要是由于java.lang.UnsatisfiedLinkErrorAndroid 7.0、8.1和9版本所发生的。
我已经在手机和包括所有架构在内的多个仿真器上测试了该应用程序。我将应用程序作为android-app-bundle上传到应用程序商店,并怀疑这可能是问题的根源。
我在这里有点迷茫,因为我已经尝试了好几件事,但是到目前为止,我既不能减少出现的次数,也无法在任何设备上重现它。任何帮助将不胜感激。
我发现此资源指出Android有时无法解压缩外部库。因此,他们创建了一个ReLinker库,该库将尝试从压缩的应用程序中获取库:
不幸的是,这并没有减少由于导致的崩溃数量java.lang.UnsatisfiedLinkError。我继续在线研究并找到了这篇文章,这表明问题出在64位库中。因此,我删除了64位库(该应用程序仍可在所有设备上运行,因为64位架构也可以执行32位库)。但是,错误仍然会以与以前相同的频率发生。
通过google-play-console,我得到了以下崩溃报告:
java.lang.UnsatisfiedLinkError:
at ch.fidelisfactory.pluspoints.Core.Wrapper.callCoreEndpointJNI (Wrapper.java)
at ch.fidelisfactory.pluspoints.Core.Wrapper.a (Wrapper.java:9)
at ch.fidelisfactory.pluspoints.Model.Exam.a (Exam.java:46)
at ch.fidelisfactory.pluspoints.SubjectActivity.i (SubjectActivity.java:9)
at ch.fidelisfactory.pluspoints.SubjectActivity.onCreate (SubjectActivity.java:213)
at android.app.Activity.performCreate (Activity.java:7136)
at android.app.Activity.performCreate (Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2908)
at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3063)
at android.app.servertransaction.LaunchActivityItem.execute (LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1823)
at android.os.Handler.dispatchMessage (Handler.java:107)
at android.os.Looper.loop (Looper.java:198)
at android.app.ActivityThread.main (ActivityThread.java:6729)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:876)
Run Code Online (Sandbox Code Playgroud)
该Wrapper.java …
java java-native-interface android unsatisfiedlinkerror android-app-bundle