abcd8912751 2016-12-08 08:17 采纳率: 50%
浏览 1778

在Android使用MappedByteBuffer写入遇到对齐访问相关问题,SIGBUS报错

各位大神,本人在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}

代码在楼下贴出

  • 写回答

2条回答

  • abcd8912751 2016-12-08 08:17
    关注
    
    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();
           }
       }
    
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献