各位大神,本人在Android环境使用FTPClient下载文件,之前使用RandomAccessfile进行多线程并发写入,速率较慢,百度一番后使用Mappedbytebuffer,但是有时报 Fatal signal 7 (SIGBUS) at 0x7cc73000 (code=2)错误会直接中断APP,希望大神给予帮助,我的代码中没有操作C/C++,不知道如何实现对齐访问,恳请指点,谢谢
报错的Logcat如下:
12-05 16:24:16.850 10110-10279/com.ftp.instant A/libc: Fatal signal 7 (SIGBUS) at 0x7cc73000 (code=2), thread 10279 (Thread-161)
12-05 16:24:16.950 155-155/? I/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
12-05 16:24:16.950 155-155/? I/DEBUG: Build fingerprint: 'Android/samsung/samsung:4.4.2/KOT49H/3.7.3.1019:userdebug/test-keys'
12-05 16:24:16.950 155-155/? I/DEBUG: Revision: '0'
12-05 16:24:16.950 155-155/? I/DEBUG: pid: 10110, tid: 10279, name: Thread-161 >>> com.ftp.instant <<<
12-05 16:24:16.950 155-155/? I/DEBUG: signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 7cc73000
12-05 16:24:16.990 155-155/? I/DEBUG: backtrace:
12-05 16:24:16.990 155-155/? I/DEBUG: #00 pc 0003e54a /system/lib/libc.so
12-05 16:24:16.990 155-155/? I/DEBUG: stack:
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7924 00000410
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7928 00000080
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c792c b4ddba92 /system/lib/libdvm.so
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7930 b4ecacb0 /system/lib/libdvm.so
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7934 24b00005
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7938 00000400
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c793c b4d68669 /system/lib/libdvm.so
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7940 b8f7f908 [heap]
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7944 24b00005
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7948 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c794c 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7950 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7954 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7958 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c795c b4ecacb0 /system/lib/libdvm.so
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7960 b8f7f860 [heap]
12-05 16:24:16.990 155-155/? I/DEBUG: #00 7d0c7964 00000400
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7968 b8f7f860 [heap]
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c796c b4d6a70f /system/lib/libdvm.so
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7970 7cc72d54 /storage/emulated/0/ftptmp/ftp5m
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7974 9515dd4c /dev/ashmem/dalvik-heap (deleted)
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7978 00000400
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c797c 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7980 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7984 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7988 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c798c 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7990 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7994 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c7998 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c799c 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: 7d0c79a0 00000000
12-05 16:24:16.990 155-155/? I/DEBUG: memory map around fault addr 7cc73000:
12-05 16:24:16.990 155-155/? I/DEBUG: 7cac6000-7cc72000 rw- /storage/emulated/0/ftptmp/ftp5m
12-05 16:24:16.990 155-155/? I/DEBUG: 7cc72000-7ce1d000 rw- /storage/emulated/0/ftptmp/ftp5m
12-05 16:24:16.990 155-155/? I/DEBUG: 7ce1d000-7cfc8000 rw- /storage/emulated/0/ftptmp/ftp5m
12-05 16:24:17.040 475-498/system_process I/BootReceiver: Copying /data/tombstones/tombstone_05 to DropBox (SYSTEM_TOMBSTONE)
12-05 16:24:17.040 475-10284/system_process W/ActivityManager: Force finishing activity com.ftp.instant/.MainActivity
12-05 16:24:17.050 475-514/system_process W/InputDispatcher: channel '4a99005c com.ftp.instant/com.ftp.instant.MainActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9
12-05 16:24:17.050 475-514/system_process E/InputDispatcher: channel '4a99005c com.ftp.instant/com.ftp.instant.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
12-05 16:24:17.070 475-498/system_process D/dalvikvm: GC_FOR_ALLOC freed 654K, 18% free 9730K/11784K, paused 30ms, total 31ms
12-05 16:24:17.080 475-486/system_process W/InputDispatcher: Attempted to unregister already unregistered input channel '4a99005c com.ftp.instant/com.ftp.instant.MainActivity (server)'
12-05 16:24:17.080 475-486/system_process I/WindowState: WIN DEATH: Window{4a99005c u0 com.ftp.instant/com.ftp.instant.MainActivity}
代码在楼下贴出
package com.ftp.utils;
import android.text.TextUtils;
import de.greenrobot.event.EventBus;
import com.ftp.bean.CheckEvent;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import rx.Observable;
import rx.Subscriber;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.net.SocketTimeoutException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.IllegalFormatCodePointException;
import static com.ftp.utils.Utils.getDownloadfile;
import static com.ftp.utils.Utils.isStop;
/**
* 使用FTPClient下载FTP服务器文件
*/
public class DownloadRunnable implements Runnable {
private EventBus eventBus;
private FTPClient ftpClient;
private int threadno;//当前线程编号
private int threadnum;//线程总数
private String remotepath;//远端文件路径
private MappedByteBuffer bytebuffer;//内存映射缓冲区
private long bufferMax; //缓冲区允许放置的字节级数据量
private long currentPos; //缓冲区中未刷入内存的大小即缓冲区写入模式下的起始位置
private RandomAccessFile accessFile; //可随意写入的文件实例
private FileChannel fileChannel;
public DownloadRunnable(FTPClient client, int threadno, int threadnum) {
this.ftpClient = client;
this.threadno = threadno;
this.threadnum = threadnum;
this.remotepath = "/ltedown/ftp5m";
if (!TextUtils.isEmpty(Utils.getRemotePath()))
this.remotepath = Utils.getRemotePath();
this.bufferMax=512*1024; //设置允许的512KB的缓存数
setRandomAccessFile();
}
@Override
public void run() {
try {
showLog(threadno + "线程 开始下载");
//在这里计算文件的起始值
long require_length, start = 0, localsize = 0;//文件起始值,需下载的长度,已下载的长度
long totalFileSize = Utils.getTotalFileSize();//远端文件的总长度
require_length = totalFileSize / threadnum;
start = (threadno - 1) * require_length;
if (totalFileSize % threadnum != 0)
{
if (threadno == threadnum)
require_length = require_length + totalFileSize % threadnum;
}
ftpClient.setRestartOffset(start);
InputStream input = ftpClient.retrieveFileStream(remotepath);
if (input == null) {
showLog(threadno + "线程无法获取InputStream");
}
fileChannel=accessFile.getChannel();
bytebuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, start, require_length);
showLog(threadno + "线程成功获取Map");
long tmp;
int length = 0;
byte[] b = new byte[1024];
setCurrentPos(0); //开始写入前设置起始位置为0
while ((length = input.read(b)) != -1) {
if (isStop())
break;
if(length==0)
showLog(threadno + "线程获取byte数为0");
if(getCurrentPos()+length>=bufferMax)
{
flush(); //当缓冲区未处理数据达到Max时flush数据
}
tmp = localsize + length;
if (tmp >= require_length)
{
length = (int) (require_length - localsize);
bytebuffer.put(b, 0, length);
addCurrentPos(length);
Utils.addFileSize(length);
localsize = localsize + length;
break;
}
showLog(threadno + "线程 当前tmp大小"+tmp);
bytebuffer.put(b, 0, length);
addCurrentPos(length);
Utils.addFileSize(length);
localsize = localsize + length;
}
input.close();
showLog(threadno + "线程" + " 下载:" + localsize + "/" + require_length);
if (!isStop())
showLog(threadno + "线程" + " 下载完成");
} catch (Exception e) {
showLog(threadno + "线程 捕捉到下载异常");
Utils.ftpRelatedStatus.setDownloadError(true);
e.printStackTrace();
} finally {
try {
//测试完成在这里作 传出信号的操作且无论下载过程有无异常均上报下载结束
Utils.addFinish();
if (accessFile != null) {
unmap(); //释放资源,释放前会flush数据
fileChannel.close();
accessFile.close();
}
ftpClient.completePendingCommand();
ftpClient.logout();
ftpClient.disconnect();
showLog(threadno + "线程 结束战斗");
}
catch (IOException e) {
showLog(threadno + "线程 FTPClient释放异常");
e.printStackTrace();
}
}
}
private synchronized void flush()
{
if(bytebuffer!=null)
bytebuffer.force();
setCurrentPos(0);
}
private void showLog(String s) {
Utils.showLog(s);
}
/**
* 显式回收MappedByteBuffer实例
*/
private void unmap() {
flush(); //刷入数据
if(bytebuffer==null)
return;
bytebuffer.clear();
bytebuffer=null;
// System.gc();
}
public void setRemotepath(String remotepath) {
this.remotepath = remotepath;
}
public long getCurrentPos() {
return currentPos;
}
public void setCurrentPos(long currentPos) {
this.currentPos = currentPos;
}
public void addCurrentPos(int variable)
{
setCurrentPos(this.currentPos + variable);
}
public synchronized void setRandomAccessFile()
{
try {
accessFile = getDownloadfile(remotepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
想问下你后来是怎么解决的?