咖啡伴侶

          呆在上海
          posts - 163, comments - 156, trackbacks - 0, articles - 2
          MappedByteBuffer是java nio引入的文件內(nèi)存映射方案,讀寫性能極高。NIO最主要的就是實(shí)現(xiàn)了對異步操作的支持。其中一種通過把一個(gè)套接字通道(SocketChannel)注冊到一個(gè)選擇器(Selector)中,不時(shí)調(diào)用后者的選擇(select)方法就能返回滿足的選擇鍵(SelectionKey),鍵中包含了SOCKET事件信息。這就是select模型。
              SocketChannel的讀寫是通過一個(gè)類叫ByteBuffer(java.nio.ByteBuffer)來操作的.這個(gè)類本身的設(shè)計(jì)是不錯(cuò)的,比直接操作byte[]方便多了. ByteBuffer有兩種模式:直接/間接.間接模式最典型(也只有這么一種)的就是HeapByteBuffer,即操作堆內(nèi)存 (byte[]).但是內(nèi)存畢竟有限,如果我要發(fā)送一個(gè)1G的文件怎么辦?不可能真的去分配1G的內(nèi)存.這時(shí)就必須使用"直接"模式,即 MappedByteBuffer,文件映射.
               先中斷一下,談?wù)劜僮飨到y(tǒng)的內(nèi)存管理.一般操作系統(tǒng)的內(nèi)存分兩部分:物理內(nèi)存;虛擬內(nèi)存.虛擬內(nèi)存一般使用的是頁面映像文件,即硬盤中的某個(gè)(某些)特殊的文件.操作系統(tǒng)負(fù)責(zé)頁面文件內(nèi)容的讀寫,這個(gè)過程叫"頁面中斷/切換". MappedByteBuffer也是類似的,你可以把整個(gè)文件(不管文件有多大)看成是一個(gè)ByteBuffer.MappedByteBuffer 只是一種特殊的 ByteBuffer ,即是ByteBuffer的子類。 MappedByteBuffer 將文件直接映射到內(nèi)存(這里的內(nèi)存指的是虛擬內(nèi)存,并不是物理內(nèi)存)。通常,可以映射整個(gè)文件,如果文件比較大的話可以分段進(jìn)行映射,只要指定文件的那個(gè)部分就可以。

          三種方式:
                        FileChannel提供了map方法來把文件影射為內(nèi)存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的從position開始的size大小的區(qū)域映射為內(nèi)存映像文件,mode指出了 可訪問該內(nèi)存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                     
          a. READ_ONLY,(只讀): 試圖修改得到的緩沖區(qū)將導(dǎo)致拋出 ReadOnlyBufferException.(MapMode.READ_ONLY)
           b. READ_WRITE(讀/寫): 對得到的緩沖區(qū)的更改最終將傳播到文件;該更改對映射到同一文件的其他程序不一定是可見的。 (MapMode.READ_WRITE)
          c. PRIVATE(專用): 對得到的緩沖區(qū)的更改不會(huì)傳播到文件,并且該更改對映射到同一文件的其他程序也不是可見的;相反,會(huì)創(chuàng)建緩沖區(qū)已修改部分的專用副本。 (MapMode.PRIVATE)

          三個(gè)方法:

          a. fore();緩沖區(qū)是READ_WRITE模式下,此方法對緩沖區(qū)內(nèi)容的修改強(qiáng)行寫入文件
          b. load()將緩沖區(qū)的內(nèi)容載入內(nèi)存,并返回該緩沖區(qū)的引用
          c. isLoaded()如果緩沖區(qū)的內(nèi)容在物理內(nèi)存中,則返回真,否則返回假

          三個(gè)特性:

              調(diào)用信道的map()方法后,即可將文件的某一部分或全部映射到內(nèi)存中,映射內(nèi)存緩沖區(qū)是個(gè)直接緩沖區(qū),繼承自ByteBuffer,但相對于ByteBuffer,它有更多的優(yōu)點(diǎn):

          a. 讀取快
          b. 寫入快
          c. 隨時(shí)隨地寫入

          下面來看代碼:

          package study;
          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.nio.ByteBuffer;
          import java.nio.MappedByteBuffer;
          import java.nio.channels.FileChannel;

          public class MapMemeryBuffer {

              public static void main(String[] args) throws Exception {
                  ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024);
                  byte[] bbb = new byte[14 * 1024 * 1024];
                  FileInputStream fis = new FileInputStream("e://data/other/UltraEdit_17.00.0.1035_SC.exe");
                  FileOutputStream fos = new FileOutputStream("e://data/other/outFile.txt");
                  FileChannel fc = fis.getChannel();
                  long timeStar = System.currentTimeMillis();// 得到當(dāng)前的時(shí)間
                  fc.read(byteBuf);// 1 讀取
                  //MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
                  System.out.println(fc.size()/1024);
                  long timeEnd = System.currentTimeMillis();// 得到當(dāng)前的時(shí)間
                  System.out.println("Read time :" + (timeEnd - timeStar) + "ms");
                  timeStar = System.currentTimeMillis();
                  fos.write(bbb);//2.寫入
                  //mbb.flip();
                  timeEnd = System.currentTimeMillis();
                  System.out.println("Write time :" + (timeEnd - timeStar) + "ms");
                  fos.flush();
                  fc.close();
                  fis.close();
              }

          }

          運(yùn)行結(jié)果:
          14235
          Read time :24ms
          Write time :21ms
          我們把標(biāo)注1和2語句注釋掉,換成它們下面的被注釋的那條語句,再來看運(yùn)行效果。
          14235
          Read time :2ms
          Write time :0ms
          可以看出速度有了很大的提升。MappedByteBuffer的確快,但也存在一些問題,主要就是內(nèi)存占用和文件關(guān)閉等不確定問題。被MappedByteBuffer打開的文件只有在垃圾收集時(shí)才會(huì)被關(guān)閉,而這個(gè)點(diǎn)是不確定的。在javadoc里是這么說的:
          A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself 
          is garbage-collected.

          這里提供一種解決方案:
          AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
              try {
                Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
                getCleanerMethod.setAccessible(true);
                sun.misc.Cleaner cleaner = (sun.misc.Cleaner)
                getCleanerMethod.invoke(byteBuffer, new Object[0]);
                cleaner.clean();
              } catch (Exception e) {
                e.printStackTrace();
              }
              return null;
            }
          });

          主站蜘蛛池模板: 浏阳市| 长垣县| 银川市| 苏尼特右旗| 邵东县| 苍溪县| 高邑县| 肃南| 吐鲁番市| 津南区| 木里| 甘洛县| 崇左市| 龙口市| 松江区| 大宁县| 墨竹工卡县| 四子王旗| 边坝县| 夏邑县| 张家口市| 巩留县| 黄山市| 化德县| 广丰县| 西宁市| 如东县| 射洪县| 肥乡县| 台安县| 丰城市| 那曲县| 易门县| 东兰县| 呈贡县| 保康县| 资源县| 电白县| 古田县| 确山县| 齐齐哈尔市|