一、page cache
操作系统为程序分配内存并不是按照一个一个来字节分配的,而是把整个内存切分成一个一个小的4k的内存块来分配的。这样一个个小的4k内存块,被称为page,操作系统这样的做的目的是为了提升性能。linux可以通过“_getconf PAGESIZE_”命令来查看系统数设置的page大小。
操作系统往文件中写入数据时为了提高性能不会直接往硬盘中写入,而是先往内存中写入数据,而内存又被拆成一个个page,等page达到一定的占用比率才会通过LRU或者LFU的算法找出该删掉的page,然后再把page中的数据一次性地写入磁盘中。这种内存临时存储硬盘的数据的page,被称为page cache。 但是page cahe有一个致命的问题, 就是内存的存储是临时的,一旦遇到断电异常会直接丢失内存中的数据。
二、ByteBuffer、RandomAccessFile
import org.junit.Test;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.MappedByteBuffer;import java.nio.channels.FileChannel;public class OSFileIO {static byte[] data = "123456789\n".getBytes();static String path = "/root/testfileio/out.txt";public static void main(String[] args) throws Exception {switch ( args[0]) {case "0" :testBasicFileIO();break;case "1":testBufferedFileIO();break;case "2" :testRandomAccessFileWrite();case "3":// whatByteBuffer();default:}}//最基本的file写public static void testBasicFileIO() throws Exception {File file = new File(path);FileOutputStream out = new FileOutputStream(file);while(true){Thread.sleep(10);out.write(data);}}//测试buffer文件IO// jvm 8kB syscall write(8KBbyte[])public static void testBufferedFileIO() throws Exception {File file = new File(path);BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));while(true){Thread.sleep(10);out.write(data);}}//测试文件NIOpublic static void testRandomAccessFileWrite() throws Exception {RandomAccessFile raf = new RandomAccessFile(path, "rw");raf.write("hello mashibing\n".getBytes());raf.write("hello seanzhou\n".getBytes());System.out.println("write------------");System.in.read();raf.seek(4);raf.write("ooxx".getBytes());System.out.println("seek---------");System.in.read();FileChannel rafchannel = raf.getChannel();//mmap 堆外 和文件映射的 byte not objtectMappedByteBuffer map = rafchannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096);map.put("@@@".getBytes()); //不是系统调用 但是数据会到达 内核的pagecache//曾经我们是需要out.write() 这样的系统调用,才能让程序的data 进入内核的pagecache//曾经必须有用户态内核态切换//mmap的内存映射,依然是内核的pagecache体系所约束的!!!//换言之,丢数据//你可以去github上找一些 其他C程序员写的jni扩展库,使用linux内核的Direct IO//直接IO是忽略linux的pagecache//是把pagecache 交给了程序自己开辟一个字节数组当作pagecache,动用代码逻辑来维护一致性/dirty。。。一系列复杂问题System.out.println("map--put--------");System.in.read();// map.force(); // flushraf.seek(0);ByteBuffer buffer = ByteBuffer.allocate(8192);// ByteBuffer buffer = ByteBuffer.allocateDirect(1024);int read = rafchannel.read(buffer); //buffer.put()System.out.println(buffer);buffer.flip();System.out.println(buffer);for (int i = 0; i < buffer.limit(); i++) {Thread.sleep(200);System.out.print(((char)buffer.get(i)));}}@Testpublic void whatByteBuffer(){// ByteBuffer buffer = ByteBuffer.allocate(1024);ByteBuffer buffer = ByteBuffer.allocateDirect(1024);System.out.println("postition: " + buffer.position());System.out.println("limit: " + buffer.limit());System.out.println("capacity: " + buffer.capacity());System.out.println("mark: " + buffer);buffer.put("123".getBytes());System.out.println("-------------put:123......");System.out.println("mark: " + buffer);buffer.flip(); //读写交替System.out.println("-------------flip......");System.out.println("mark: " + buffer);buffer.get();System.out.println("-------------get......");System.out.println("mark: " + buffer);buffer.compact();System.out.println("-------------compact......");System.out.println("mark: " + buffer);buffer.clear();System.out.println("-------------clear......");System.out.println("mark: " + buffer);}}
