其他
如果面试被问“零拷贝”,你会怎么办?
点击上方蓝色“后端面试那些事儿”,选择“设为星标”
学最好的别人,做最好的我们
来源 | https://my.oschina.net/OutOfMemory/blog/3034514
I/O概念 1.缓冲区 2.虚拟内存 3.mmap+write方式 4.sendfile方式 Java零拷贝 1.MappedByteBuffer 2.DirectByteBuffer 3.Channel-to-Channel传输 Netty零拷贝 其他零拷贝 总结
前言
I/O概念
1.缓冲区
2.虚拟内存
3.mmap+write方式
4.sendfile方式
Java零拷贝
1.MappedByteBuffer
public class MappedByteBufferTest {
public static void main(String[] args) throws Exception {
File file = new File("D://db.txt");
long len = file.length();
byte[] ds = new byte[(int) len];
MappedByteBuffer mappedByteBuffer = new FileInputStream(file).getChannel().map(FileChannel.MapMode.READ_ONLY, 0,
len);
for (int offset = 0; offset < len; offset++) {
byte b = mappedByteBuffer.get();
ds[offset] = b;
}
Scanner scan = new Scanner(new ByteArrayInputStream(ds)).useDelimiter(" ");
while (scan.hasNext()) {
System.out.print(scan.next() + " ");
}
}
}
主要通过FileChannel提供的map()来实现映射,map()方法如下:
public abstract MappedByteBuffer map(MapMode mode,
long position, long size)
throws IOException;
public MappedByteBuffer map(MapMode mode, long position, long size)
throws IOException
{
...省略...
int pagePosition = (int)(position % allocationGranularity);
long mapPosition = position - pagePosition;
long mapSize = size + pagePosition;
try {
// If no exception was thrown from map0, the address is valid
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError x) {
// An OutOfMemoryError may indicate that we've exhausted memory
// so force gc and re-attempt map
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException y) {
Thread.currentThread().interrupt();
}
try {
addr = map0(imode, mapPosition, mapSize);
} catch (OutOfMemoryError y) {
// After a second OOME, fail
throw new IOException("Map failed", y);
}
}
// On Windows, and potentially other platforms, we need an open
// file descriptor for some mapping operations.
FileDescriptor mfd;
try {
mfd = nd.duplicateForMapping(fd);
} catch (IOException ioe) {
unmap0(addr, mapSize);
throw ioe;
}
assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0);
int isize = (int)size;
Unmapper um = new Unmapper(addr, mapSize, isize, mfd);
if ((!writable) || (imode == MAP_RO)) {
return Util.newMappedByteBufferR(isize,
addr + pagePosition,
mfd,
um);
} else {
return Util.newMappedByteBuffer(isize,
addr + pagePosition,
mfd,
um);
}
}
2.DirectByteBuffer
ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(100);
如上开辟了100字节的直接内存空间;
3.Channel-to-Channel传输
public class ChannelTransfer {
public static void main(String[] argv) throws Exception {
String files[]=new String[1];
files[0]="D://db.txt";
catFiles(Channels.newChannel(System.out), files);
}
private static void catFiles(WritableByteChannel target, String[] files)
throws Exception {
for (int i = 0; i < files.length; i++) {
FileInputStream fis = new FileInputStream(files[i]);
FileChannel channel = fis.getChannel();
channel.transferTo(0, channel.size(), target);
channel.close();
fis.close();
}
}
}
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;
Netty零拷贝
public class CompositeChannelBuffer extends AbstractChannelBuffer {
private final ByteOrder order;
private ChannelBuffer[] components;
private int[] indices;
private int lastAccessedComponentId;
private final boolean gathering;
public byte getByte(int index) {
int componentId = componentId(index);
return components[componentId].getByte(index - indices[componentId]);
}
...省略...
其他零拷贝
总结
往期推荐
2020-07-06
2020-07-05
2020-07-04
2020-07-03
2020-07-02
一起进大厂,每日学干货
关注我,不迷路