jvm hotspot 源码分析 RandomAccessfile vs FileChannel 写文件
来源:互联网 发布:linux recvfrom 编辑:程序博客网 时间:2024/06/10 05:58
RandomAccessFile 和 FileChannel 是常用的写文件的方式,而一般都会推荐使用FileChannelImpl ,同事做了个测试,却发现FileChannelImpl写文件的性能比RandomAccessFile差。
调用接口:
RandomAccessFile.write(byte[] bytes)
FileChannel.write(ByteBuffer src)
FileChannel
实现类FileChannelImpl.write(ByteBuffer src), 调用了IOUtil.write 方法
static int write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd, Object lock) throws IOException { if (src instanceof DirectBuffer) return writeFromNativeBuffer(fd, src, position, nd, lock); // Substitute a native buffer int pos = src.position(); int lim = src.limit(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); ByteBuffer bb = null; try { bb = Util.getTemporaryDirectBuffer(rem); bb.put(src); bb.flip(); // Do not update src until we see how many bytes were written src.position(pos); int n = writeFromNativeBuffer(fd, bb, position, nd, lock); if (n > 0) { // now update src src.position(pos + n); } return n; } finally { Util.offerFirstTemporaryDirectBuffer(bb); } }
如果ByteBuffer 是directByteBuffer,直接调用函数writeFromNativeBuffer复制
如果不是DirectByteBuffer,会从DirectByteBuffer 池中取一个DirectByteBuffer, 将ByteBuffer中的byte[]数组复制到DirectByteBuffer中,为了避免allocate 内存的开销,对同一个线程会有DirectByteBuffer池的缓存,指定不同的大小,getTemporaryDirectBuffer方法就是从池里找到一个比自己大的DirectByteBuffer。
DirectByteBuffer 和 HeapByteBuffer的区别
在java中关于DirectByteBuffer 和传统的HeapByteBuffer 的区别是,DirectByteBuffer 是一块真实的内存块,里面存放的是byte数组的内容,而HeapByteBuffer里面只是数组的引用。这样就可以理解DirectByteBuffer 只要2个重要元素就够了,一个是内存的起始地址,一个是内存块的长度。一旦要和内核或者别的语言操作的时候,DirectByteBuffer是最好的选择,没有byte[] 或者java的object的结构,只要通过访问地址和长度,就能访问到数据本身,而在sun的unsafe.java里就提供了大量的直接访问内存的函数。
方法writeFromNativeBuffer 最后通过调用FileDispatcher.c linux中调用的就是c 函数pwrite64写文件
RandomAccessFile
在RandomAccessFile.write 中,直接调用的就是native方法,也就是io_util.c中writeBytes 方法
voidwriteBytes(JNIEnv *env, jobject this, jbyteArray bytes, jint off, jint len, jfieldID fid){ int n, datalen; char stackBuf[BUF_SIZE]; char *buf = 0; FD fd; if (IS_NULL(bytes)) {JNU_ThrowNullPointerException(env, 0);return; } datalen = (*env)->GetArrayLength(env, bytes); if ((off < 0) || (off > datalen) || (len < 0) || ((off + len) > datalen) || ((INT_MAX - off) < len)) { JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);return; } if (len == 0) { return; } else if (len > BUF_SIZE) { buf = malloc(len);if (buf == 0) { JNU_ThrowOutOfMemoryError(env, 0); return;} } else { buf = stackBuf; } fd = GET_FD(this, fid); (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf); if (!(*env)->ExceptionOccurred(env)) { off = 0;while (len > 0) { n = IO_Write(fd, buf+off, len); if (n == JVM_IO_ERR) { JNU_ThrowIOExceptionWithLastError(env, "Write error");break; } else if (n == JVM_IO_INTR) { JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);break; } off += n; len -= n;} } if (buf != stackBuf) { free(buf); }}
区别:
第一: 两个函数的参数是不一样的,一个是byte数组,一个是bytebuffer, 对filechannel来说,如果传进去是directbuffer,不涉及到内存的复制,那么性能是最好的。
第二: 复制byte数组到内存中,GetByteArrayRegion 用的是memcpy 而 filechannel AMD64用的是memmove ,对别的cpu直接使用汇编, 而memcpy的性能比memove高。
强制sync
在linux中,write 函数只能保证把内存复制到page cache中,需要调用fdatasync,fsync 来强制提交到磁盘中去,一般在db, hadoop, kv 中比较重要的事务日志文件都需要强制sync 保证数据真的在磁盘中。
也就是函数 filechannel.force 和 RandomAccessFile.getFD().sync(); 但这2个函数是性能比较差的。
如何提高sync的性能
1. 用direct_io 去open file
2. 调用 sync_file_range,去跟新部分内容,而不是sync整个文件
long sync_file_range(int fd, loff_t offset, loff_t nbytes, int flags);
但这2中方式在java里都没有支持,也是java以后可以提高的地方。
- jvm hotspot 源码分析 RandomAccessfile vs FileChannel 写文件
- RandomAccessFile、FileChannel、MappedByteBuffer读写文件
- Hotspot jvm源码分析 Java中的Intrinsics
- RandomAccessFile 源码分析
- JVM/HotSpot-Java对象头的HotSpot实现分析
- 【Java8源码分析】NIO包-FileChannel
- HotSpot JVM
- JVM--hotspot
- Java对文件的读、写随机访问,RandomAccessFile类的使用分析
- Java对文件的读、写随机访问,RandomAccessFile类的使用分析
- Java对文件的读、写随机访问,RandomAccessFile类的使用分析
- 利用FileChannel完成文件的读、写、复制
- 利用FileChannel完成文件的读、写、复制
- RandomAccessFile 和 FileChannel【memory-mapped files】
- HDFS dfsclient写文件过程 源码分析
- HDFS dfsclient写文件过程 源码分析
- Flume - FileChannel源码详解
- Sun Microsystems’HotSpot JVM
- 基于已有cramfs文件系统制作cramfs文件系统
- OpenGLES 1.1教程(二)-简单图形的绘制
- iphone中GPS精确定位及反向获取地址信息
- OpenGl纹理映射
- qt 背景随窗口变化
- jvm hotspot 源码分析 RandomAccessfile vs FileChannel 写文件
- DM365软件环境搭建步骤
- centos 下centos源码下载安装
- 数据库出现 enq: TX - row lock contention
- Linux mannual page to txt
- Shadowmap
- linux启动流程
- RSA 学习
- SVM百家争鸣之多分类超球支持向量机