gpt4 book ai didi

java - JNI 分配损坏的堆

转载 作者:行者123 更新时间:2023-11-30 03:33:31 25 4
gpt4 key购买 nike

然后下面的代码有一个意想不到的行为:File 参数在运行时变成了一个 DirectoryListingPerfTest。

我想 java 堆已损坏,我的 native 代码没有使用正确的参数调用它。

Java代码如下:

public class DirectoryListingPerfTest implements FileFilter {

private final SortedSet<File> _dirs = new TreeSet<>();

@SuppressWarnings("cast")
@Override
public boolean accept( File pathname ) {
if( pathname instanceof File ) {
_dirs.add( pathname );
}
else {
System.err.println( pathname.getClass());
}
return false;
}

static native void find( String path, FileFilter listener );

public static void main( String[] args ) {
System.loadLibrary( "fs_DirectoryListingPerfTest" );
final DirectoryListingPerfTest ff = new DirectoryListingPerfTest();
long atStart, elapsed;
atStart = System.nanoTime();
find( "/usr", ff );
elapsed = System.nanoTime() - atStart;
System.err.printf( "native(1): %,9.2f ms\n", elapsed / 1.0E+06 );
atStart = System.nanoTime();
find( "/usr", ff );
elapsed = System.nanoTime() - atStart;
System.err.printf( "native(2): %,9.2f ms\n", elapsed / 1.0E+06 );
}
}

这是 C++ JNI 代码:

static jclass    File;
static jmethodID FileCtor;

static void Java_fs_DirectoryListingPerfTest_find_r(
JNIEnv * env,
const char * path,
jobject listener,
jmethodID accept )
{
jstring jPath = env->NewStringUTF( path );
jobject file = env->NewObject( File, FileCtor, jPath );
jobject gFile = env->NewGlobalRef( file );
env->CallBooleanMethod( listener, accept, gFile );
DIR * dir = opendir( path );
if( dir ) {
struct dirent * entry;
while(( entry = readdir( dir )) != NULL ) {
if( ( 0 == strcmp( entry->d_name, "." ))
||( 0 == strcmp( entry->d_name, ".." )))
{
continue;
}
if( entry->d_type == DT_DIR ) {
char * buffer = (char *)malloc(
strlen( path ) + 1 + strlen( entry->d_name ) + 1 );
strcpy( buffer, path );
strcat( buffer, "/" );
strcat( buffer, entry->d_name );
Java_fs_DirectoryListingPerfTest_find_r(
env, buffer, listener, accept );
free( buffer );
}
}
closedir( dir );
}
}

JNIEXPORT void JNICALL Java_fs_DirectoryListingPerfTest_find(
JNIEnv * env,
jclass clazz,
jstring jpath,
jobject listener )
{
if( File == NULL ) {
File = env->FindClass( "java/io/File" );
FileCtor = env->GetMethodID( File, "<init>", "(Ljava/lang/String;)V");
}
jclass FileFilter = env->GetObjectClass( listener );
jmethodID accept =
env->GetMethodID( FileFilter, "accept", "(Ljava/io/File;)Z");
const char * path = env->GetStringUTFChars( jpath, JNI_FALSE );
Java_fs_DirectoryListingPerfTest_find_r( env, path, listener, accept );
env->ReleaseStringUTFChars( jpath, path );
}

这是执行轨迹:

native(1):    584,76 ms
class fs.DirectoryListingPerfTest
class fs.DirectoryListingPerfTest
... (a lot !)
class fs.DirectoryListingPerfTest
Exception in thread "main" java.lang.ClassCastException: fs.DirectoryListingPerfTest cannot be cast to java.lang.Comparable
at java.util.TreeMap.put(TreeMap.java:565)
at java.util.TreeSet.add(TreeSet.java:255)
at fs.DirectoryListingPerfTest.accept(DirectoryListingPerfTest.java:16)
at fs.DirectoryListingPerfTest.find(Native Method)
at fs.DirectoryListingPerfTest.main(DirectoryListingPerfTest.java:91)

最佳答案

您不能在调用之间缓存 Java 对象。这段代码是错误的:

static jclass    File;
static jmethodID FileCtor;

...

if( File == NULL ) {
File = env->FindClass( "java/io/File" );
FileCtor = env->GetMethodID( File, "<init>", "(Ljava/lang/String;)V");
}

如果要缓存 Java 值,一般需要创建一个全局引用。见:

关于java - JNI 分配损坏的堆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42796371/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com