我写了一个简单的Android原生函数,它获取文件名和更多参数,并通过mmapping(mmap)读取文件的内存。
因为它是mmap,所以我不需要调用“read()”所以我只是从mmap()返回的地址中memcpy()。
但是,在某些地方我得到一个SIGSEGV可能是因为我试图访问一个我不允许的内存。但我不明白为什么,我已经要求映射所有文件的内存了!
我正在附加我的代码和我得到的错误:
修改
我修复了无终止循环,但在读取了25001984个字节后仍然得到了SIGSEGV。 该函数适用于这些参数: jn_bytes = 100,000,000 jbuffer_size = 8192 jshared = jpopulate = jadvice = 0
void Java_com_def_benchmark_Benchmark_testMmapRead(JNIEnv* env, jobject javaThis,
jstring jfile_name, unsigned int jn_bytes, unsigned int jbuffer_size, jboolean jshared, jboolean jpopulate, jint jadvice) {
const char *file_name = env->GetStringUTFChars(jfile_name, 0);
/* *** start count *** */
int fd = open(file_name, O_RDONLY);
//get the size of the file
size_t length = lseek(fd, 0L, SEEK_END);
lseek(fd, 0L, SEEK_SET);
length = length>jn_bytes?jn_bytes:length;
// man 2 mmap: MAP_POPULATE is only supported for private mappings since Linux 2.6.23
int flags = 0;
if (jshared) flags |= MAP_SHARED; else flags |= MAP_PRIVATE;
if(jpopulate) flags |= MAP_POPULATE;
//int flags = MAP_PRIVATE;
int * addr = reinterpret_cast<int *>(mmap(NULL, length , PROT_READ, flags , fd, 0));
if (addr == MAP_FAILED) {
__android_log_write(ANDROID_LOG_ERROR, "NDK_FOO_TAG", strerror(errno));
return;
}
int * initaddr = addr;
if(jadvice > 0)
madvise(addr,length,jadvice==1?(MADV_SEQUENTIAL|MADV_WILLNEED):(MADV_DONTNEED));
close(fd);
char buffer[jbuffer_size];
void *ret_val = buffer;
int read_length = length;
while(ret_val == buffer || read_length<jbuffer_size) {
/*****GETTING SIGSEGV SOMWHERE HERE IN THE WHILE************/
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
munmap(initaddr,length);
/* stop count */
env->ReleaseStringUTFChars(jfile_name, file_name);
}
和错误日志:
15736^done
(gdb)
15737 info signal SIGSEGV
&"info signal SIGSEGV\n"
~"Signal Stop\tPrint\tPass to program\tDescription\n"
~"SIGSEGV Yes\tYes\tYes\t\tSegmentation fault\n"
15737^done
(gdb)
15738-stack-list-arguments 0 0 0
15738^done,stack-args=[frame={level="0",args=[]}]
(gdb)
15739-stack-list-locals 0
15739^done,locals=[]
(gdb)
答案 0 :(得分:3)
这里有一个很大的问题:
addr+=jbuffer_size;
您将addr
提升sizeof(int) * jbuffer_size
个字节,而您只想将其增加jbuffer_size
个字节。
我的系统上的sizeof(int)
是4,因此您在循环中大约有25%的速度崩溃,因为每个addr
增加了4倍。迭代。
答案 1 :(得分:1)
此循环永不终止,因为ret_val
始终等于buffer
void *ret_val = buffer;
int read_length = length;
while(ret_val == buffer || read_length<jbuffer_size) {
/*****GETTING SIGSEGV SOMWHERE HERE IN THE WHILE************/
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
memcpy
总是返回它的第一个参数,因此ret_val
永远不会改变。
答案 2 :(得分:1)
while
循环是无限的:
while(ret_val == buffer || read_length<jbuffer_size) {
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
因为memcpy()
总是返回desintation缓冲区,因此ret_val == buffer
将始终为true
(因此作为终止条件的一部分无用)。这意味着addr
在循环的每次迭代中都会增加jbuffer_size
个字节,并传递给memcpy()
,在访问无效内存时会停止。
答案 3 :(得分:1)
while(ret_val == buffer || read_length<jbuffer_size)
中的条件错误。 ret_val == buffer
将永远为真,如果read_length<jbuffer_size
在到达循环时为真,则它将始终为真,因为read_length
只会被减少(好吧,直到它下溢INT_MIN)。 / p>