一、page cache

操作系统为程序分配内存并不是按照一个一个来字节分配的,而是把整个内存切分成一个一个小的4k的内存块来分配的。这样一个个小的4k内存块,被称为page,操作系统这样的做的目的是为了提升性能。linux可以通过“_getconf PAGESIZE_”命令来查看系统数设置的page大小。
image.png
操作系统往文件中写入数据时为了提高性能不会直接往硬盘中写入,而是先往内存中写入数据,而内存又被拆成一个个page,等page达到一定的占用比率才会通过LRU或者LFU的算法找出该删掉的page,然后再把page中的数据一次性地写入磁盘中。这种内存临时存储硬盘的数据的page,被称为page cache。 但是page cahe有一个致命的问题, 就是内存的存储是临时的,一旦遇到断电异常会直接丢失内存中的数据。

二、ByteBuffer、RandomAccessFile

  1. import org.junit.Test;
  2. import java.io.BufferedOutputStream;
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.RandomAccessFile;
  6. import java.nio.ByteBuffer;
  7. import java.nio.MappedByteBuffer;
  8. import java.nio.channels.FileChannel;
  9. public class OSFileIO {
  10. static byte[] data = "123456789\n".getBytes();
  11. static String path = "/root/testfileio/out.txt";
  12. public static void main(String[] args) throws Exception {
  13. switch ( args[0]) {
  14. case "0" :
  15. testBasicFileIO();
  16. break;
  17. case "1":
  18. testBufferedFileIO();
  19. break;
  20. case "2" :
  21. testRandomAccessFileWrite();
  22. case "3":
  23. // whatByteBuffer();
  24. default:
  25. }
  26. }
  27. //最基本的file写
  28. public static void testBasicFileIO() throws Exception {
  29. File file = new File(path);
  30. FileOutputStream out = new FileOutputStream(file);
  31. while(true){
  32. Thread.sleep(10);
  33. out.write(data);
  34. }
  35. }
  36. //测试buffer文件IO
  37. // jvm 8kB syscall write(8KBbyte[])
  38. public static void testBufferedFileIO() throws Exception {
  39. File file = new File(path);
  40. BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
  41. while(true){
  42. Thread.sleep(10);
  43. out.write(data);
  44. }
  45. }
  46. //测试文件NIO
  47. public static void testRandomAccessFileWrite() throws Exception {
  48. RandomAccessFile raf = new RandomAccessFile(path, "rw");
  49. raf.write("hello mashibing\n".getBytes());
  50. raf.write("hello seanzhou\n".getBytes());
  51. System.out.println("write------------");
  52. System.in.read();
  53. raf.seek(4);
  54. raf.write("ooxx".getBytes());
  55. System.out.println("seek---------");
  56. System.in.read();
  57. FileChannel rafchannel = raf.getChannel();
  58. //mmap 堆外 和文件映射的 byte not objtect
  59. MappedByteBuffer map = rafchannel.map(FileChannel.MapMode.READ_WRITE, 0, 4096);
  60. map.put("@@@".getBytes()); //不是系统调用 但是数据会到达 内核的pagecache
  61. //曾经我们是需要out.write() 这样的系统调用,才能让程序的data 进入内核的pagecache
  62. //曾经必须有用户态内核态切换
  63. //mmap的内存映射,依然是内核的pagecache体系所约束的!!!
  64. //换言之,丢数据
  65. //你可以去github上找一些 其他C程序员写的jni扩展库,使用linux内核的Direct IO
  66. //直接IO是忽略linux的pagecache
  67. //是把pagecache 交给了程序自己开辟一个字节数组当作pagecache,动用代码逻辑来维护一致性/dirty。。。一系列复杂问题
  68. System.out.println("map--put--------");
  69. System.in.read();
  70. // map.force(); // flush
  71. raf.seek(0);
  72. ByteBuffer buffer = ByteBuffer.allocate(8192);
  73. // ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
  74. int read = rafchannel.read(buffer); //buffer.put()
  75. System.out.println(buffer);
  76. buffer.flip();
  77. System.out.println(buffer);
  78. for (int i = 0; i < buffer.limit(); i++) {
  79. Thread.sleep(200);
  80. System.out.print(((char)buffer.get(i)));
  81. }
  82. }
  83. @Test
  84. public void whatByteBuffer(){
  85. // ByteBuffer buffer = ByteBuffer.allocate(1024);
  86. ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
  87. System.out.println("postition: " + buffer.position());
  88. System.out.println("limit: " + buffer.limit());
  89. System.out.println("capacity: " + buffer.capacity());
  90. System.out.println("mark: " + buffer);
  91. buffer.put("123".getBytes());
  92. System.out.println("-------------put:123......");
  93. System.out.println("mark: " + buffer);
  94. buffer.flip(); //读写交替
  95. System.out.println("-------------flip......");
  96. System.out.println("mark: " + buffer);
  97. buffer.get();
  98. System.out.println("-------------get......");
  99. System.out.println("mark: " + buffer);
  100. buffer.compact();
  101. System.out.println("-------------compact......");
  102. System.out.println("mark: " + buffer);
  103. buffer.clear();
  104. System.out.println("-------------clear......");
  105. System.out.println("mark: " + buffer);
  106. }
  107. }