MappedByteBuffer 소결

자바 의 메모리 맵 파일 은 다음 과 같은 특징 이 있 습 니 다:
 
1.가상 메모 리 를 사용 하기 때문에 분배(map)의 메모리 크기 는 JVM 의-Xmx 매개 변수 에 제한 을 받 지 않 지만 크기 제한 이 있 습 니 다.우선 그 는 이론 적 으로 Integer.MAX 를 초과 할 수 없습니다.VALUE 는 32 비트 운영 체제 의 2G 이다.그 다음으로 실제 값 은 운영 체 제 를 사용 하지 않 아 도 다르다.win 7 32 비트 운영 체제 에서 그 는 1.5G 를 초과 할 수 없고 구체 적 으로 얼마 인지 측정 하지 못 했 으 며 무슨 원인 인지 모른다.
 
2.큰 파일 을 읽 어야 합 니 다.파일 이 1.5G 제한 을 초과 하면 다시 맵 을 하고 POSITION 매개 변 수 를 통 해 파일 뒤의 내용 을 가 져 올 수 있 습 니 다.
 
3.읽 기와 반복 읽 기 는 보통 IO 보다 빠 르 지 않 지만 단순 한 기록 은 일반 I/O 의 일반 속도 보다 못 합 니 다.이 결론 은 다음 과 같은 테스트 코드 에서 나온다.
package com.chat;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;


public class FileChannelStudy
{


    static String filename1 = "d:\\work\\code\\filechannelstudy.txt";
    static String filename2 = "d:\\work\\code\\file.txt";
    static String content = "abcdefghijk\r
"; static long size = 1024000000l; static long num = size / 10*6; static long startT = 0; static long endT = 0; public static void setStartT() { mbb = null; if(cnt %50 == 0) { System.gc(); System.out.println("call gc"); }  startT = System.currentTimeMillis(); } public static long ellipseT() { endT = System.currentTimeMillis(); long consumeT = endT - startT; System.out.println("consume time :"+ consumeT/1000 + " second"); return consumeT / 1000; } /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // readFile1(); createFile(true); preparedFile1(); preparedFile2(); } public static void createFile(boolean bReCreate) throws IOException { if(!bReCreate) { File f = new File(filename1); if(!f.exists()) f.createNewFile(); f = new File(filename2); if(!f.exists()) f.createNewFile(); } else { File f = new File(filename1); if(f.exists()) f.delete(); f.createNewFile(); f = new File(filename2); if(f.exists()) f.delete(); f.createNewFile(); } } public static void preparedFile2() throws IOException { BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(filename2)); try { System.out.println("fill file by io"); setStartT(); for (int i = 0; i < num; i++) { bo.write(content.getBytes()); } ellipseT(); } finally { if(bo != null) bo.close(); } } public static void preparedFile1() throws IOException { long mapsize = content.getBytes().length*1000000*100; long position = 0; FileChannel ch = new RandomAccessFile(filename1,"rw").getChannel(); MappedByteBuffer mbb = ch.map(MapMode.READ_WRITE, position, mapsize); int cnt = 0; try { System.out.println("fill file by nio"); setStartT(); for (int i = 0; i < num; i++) { if(mbb.remaining() < content.getBytes().length) { cnt ++; position += mbb.position(); mbb = null; if(cnt %50 == 0) { System.gc(); System.out.println("call gc"); } mbb = ch.map(MapMode.READ_WRITE, position, mapsize); } mbb.put(content.getBytes()); } ellipseT(); } finally { if(ch != null) ch.close(); } } public static void readFile1() throws IOException { long mapsize = content.getBytes().length*1000000; long position = 0; //long rper = 2000000000; long rper = 1300000000; FileChannel ch = new RandomAccessFile(filename1,"rw").getChannel(); MappedByteBuffer mbb = ch.map(MapMode.READ_WRITE, 0, rper); int rs = 102400; byte dst[] = new byte[rs]; int cnt = 0; while(mbb.hasRemaining()) { ByteBuffer bb = mbb.get(dst); cnt ++; if(cnt %50 == 0) System.out.println(bb.toString()); } } }
 
4.FileOutputStream 에 도 channel 기능 이 있 지만 메모리 맵 파일 로 파일 을 쓰 려 면 RandomAccessFile 만 사용 할 수 있 습 니 다.쓸 때 읽 기 때문에 사용 할 수 밖 에 없습니다.
 
5.그 는 다른 ByteBuffer 와 다른 점 이 있 습 니 다.다른 ByteBuffer 는 channel.write/read 로 대상 의 데 이 터 를 기록 하고 읽 어야 합 니 다.MappedByteBuffer 는 목표 에 대한 것 입 니 다.그 수정 은 PRIVATE 를 설정 하지 않 는 한 디스크 에 자동 으로 기 록 됩 니 다.
 
6.메모리 넘 침 문 제 는 크기 제한 을 제외 하고 큰 파일 을 쓸 때 끊임없이 맵 을 다시 작성 하기 때문에 메모리 가 넘 치 거나 gc 가 메모 리 를 회수 하지 못 할 수도 있 습 니 다.예 를 들 어 상기 프로그램 에서 prepareFile 1 의
 mbb = null;
                    if(cnt %50 == 0) 
                        {
                        System.gc();
                        System.out.println("call gc");
                        }

 코드 가 삭제 되면 3G 정도 에 메모리 가 넘 칩 니 다.mbb=null 만 유지 하면;5G 좌우 에 메모리 가 넘 치고,모두 유지 하면 메모리 넘 침 을 알 리 지 않 는 다.따라서 System.gc()를 수 동 으로 실행 해 야 합 니 다.
 
 
7.중국어 읽 기와 쓰기 에 있어 서 코드 를 바 꿔 야 합 니 다.
    물론 원래 io 도 코드 를 바 꿔 야 하지만 InputStreamReader 에서 문자 집합 을 지정 할 수 있 기 때문에 스스로 코드 를 쓰 지 않 아 도 됩 니 다.
    코드 를 바 꾸 지 않 으 면 UE 등의 도구 로 파일 을 열 면 난 코드 가 보이 지만 자바 의 MappedByteBuffer 로 읽 기 처 리 는 중국어 입 니 다.
    코드:
 
 public static ByteBuffer getBytes(String str)
    {//        (  )
        Charset cs = Charset.forName("GBK");
        ByteBuffer bb = ByteBuffer.wrap(str.getBytes(cs));
        return bb;
    }

    public static String getChars(ByteBuffer bb)
    {//        (  )
        Charset cs = Charset.forName("GBK");
        bb.flip();
        CharBuffer cb = cs.decode(bb);

        return cb.toString();
    }
 

좋은 웹페이지 즐겨찾기