下面的内容有些从网上搜罗的,有些属于自己总结的,总之就是给使用NIO buffer的童鞋点参考。
1、 劣势:创建和释放Direct Buffer的代价比Heap Buffer得要高;
2、 区别:Direct Buffer不是分配在堆上的,它不被GC直接管理(但Direct Buffer的JAVA对象是归GC管理的,只要GC回收了它的JAVA对象,操作系统才会释放Direct Buffer所申请的空间),它似乎给人感觉是“内核缓冲区(buffer in kernel)”。Heap Buffer则是分配在堆上的,或者我们可以简单理解为Heap Buffer就是byte[]数组的一种封装形式,查看JAVA源代码实现,Heap Buffer也的确是这样。
3、 优势:当我们把一个Direct Buffer写入Channel的时候,就好比是“内核缓冲区”的内容直接写入了Channel,这样显然快了,减少了数据拷贝(因为我们平时的read/write都是需要在I/O设备与应用程序空间之间的“内核缓冲区”中转一下的)。而当我们把一个Heap Buffer写入Channel的时候,实际上底层实现会先构建一个临时的Direct Buffer,然后把Heap Buffer的内容复制到这个临时的Direct Buffer上,再把这个Direct Buffer写出去。当然,如果我们多次调用write方法,把一个Heap Buffer写入Channel,底层实现可以重复使用临时的Direct Buffer,这样不至于因为频繁地创建和销毁Direct Buffer影响性能。
简单的说,我们需要牢记三点:
(1) 平时的read/write,都会在I/O设备与应用程序空间之间经历一个“内核缓冲区”。
(2) Direct Buffer就好比是“内核缓冲区”上的缓存,不直接受GC管理;而Heap Buffer就仅仅是byte[]字节数组的包装形式。因此把一个Direct Buffer写入一个Channel的速度要比把一个Heap Buffer写入一个Channel的速度要快。
(3) Direct Buffer创建和销毁的代价很高,所以要用在尽可能重用的地方。
E文参考REFER:
http://stackoverflow.com/questions/5670862/bytebuffer-allocate-vs-bytebuffer-allocatedirect
Operating systems perform I/O operations on memory areas. These memory areas, as far as the operating system is concerned, are contiguous sequences of bytes. It's no surprise then that only byte buffers are eligible to participate in I/O operations. Also recall that the operating system will directly access the address space of the process, in this case the JVM process, to transfer the data. This means that memory areas that are targets of I/O perations must be contiguous sequences of bytes. In the JVM, an array of bytes may not be stored contiguously in memory, or the Garbage Collector could move it at any time. Arrays are objects in Java, and the way data is stored inside that object could vary from one JVM implementation to another.
For this reason, the notion of a direct buffer was introduced.
Direct buffers are intended for interaction with channels and native I/O routines. They make a best effort to store the byte elements in a memory area that a channel can use for direct, or raw, access by using native code to tell the operating system to drain or fill the memory area directly.
Direct byte buffers are usually the best choice for I/O operations. By design, they support the most efficient I/O mechanism available to the JVM. Nondirect byte buffers can be passed to channels, but doing so may incur a performance penalty. It's usually not possible for a nondirect buffer to be the target of a native I/O operation. If you pass a nondirect ByteBuffer object to a channel for write, the channel may implicitly do the following on each call:
1. Create a temporary direct ByteBuffer object.
2. Copy the content of the nondirect buffer to the temporary buffer.
3. Perform the low-level I/O operation using the temporary buffer.
4. The temporary buffer object goes out of scope and is eventually garbage collected.
This can potentially result in buffer copying and object churn on every I/O, which are exactly the sorts of things we'd like to avoid. However, depending on the implementation, things may not be this bad. The runtime will likely cache and reuse direct buffers or perform other clever tricks to boost throughput.
If you're simply creating a buffer for one-time use, the difference is not significant.
如果我们构造一个ByteBuffer仅仅使用一次,不复用它,那么Direct Buffer和Heap Buffer没有明显的区别。两个地方我们可能通过Direct Buffer来提高性能:
1、 大文件,尽管我们Direct Buffer只用一次,但是如果内容很大,Heap Buffer的复制代价会很高,此时用Direct Buffer能提高性能。这就是为什么,当我们下载一个大文件时,服务端除了用SendFile机制,也可以用“内存映射”,把大文件映射到内存,也就是MappedByteBuffer,是一种Direct Buffer,然后把这个MappedByteBuffer直接写入SocketChannel,这样减少了数据复制,从而提高了性能。
2、 重复使用的数据,比如HTTP的错误信息,例如404呀,这些信息是每次请求,响应数据都一样的,那么我们可以把这些固定的信息预先存放在Direct Buffer中(当然部分修改Direct Buffer中的信息也可以,重要的是Direct Buffer要能被重复使用),这样把Direct Buffer直接写入SocketChannel就比写入Heap Buffer要快了。
On the other hand, if you will be using the buffer repeatedly in a high-performance scenario, you're better off allocating direct buffers and reusing them.
Direct buffers are optimal for I/O, but they may be more expensive to create than nondirect byte buffers.
The memory used by direct buffers is allocated by calling through to native, operating system-specific code, bypassing the standard JVM heap. Setting up and tearing down direct buffers could be significantly more expensive than heap-resident buffers, depending on the host operating system and JVM implementation. The memory-storage areas of direct buffers are not subject to garbage collection because they are outside the standard JVM heap.
The performance tradeoffs of using direct versus nondirect buffers can vary widely by JVM, operating system, and code design. By allocating memory outside the heap, you may subject your application to additional forces of which the JVM is unaware. When bringing additional moving parts into play, make sure that you're achieving the desired effect. I recommend the old software maxim: first make it work, then make it fast. Don't worry too much about optimization up front; concentrate first on correctness. The JVM implementation may be able to perform buffer caching or other optimizations that will give you the performance you need without a lot of unnecessary effort on your part.
分享到:
相关推荐
Buffer 是 Java 中一个非常重要的知识点,Direct Buffer 和 Heap Buffer 是两种不同的 Buffer,Direct Buffer 可以提高效率和减少GC 的频率,而 Heap Buffer 需要进行数据复制,因此效率较低。在实际开发中,应该...
Buffer分为两种类型:Heap Buffer和Direct Buffer。Heap Buffer存储在Java堆中,而Direct Buffer存储在系统内存中,直接与硬件交互,减少了Java虚拟机(JVM)的内存拷贝,提高了性能。然而,Direct Buffer可能会占用...
当Java应用程序尝试分配新的对象,但堆内存(Heap Space)不足以容纳这些对象时,就会抛出`java.lang.OutOfMemoryError: Java heap space`。此错误可能由以下几个原因引起: - 创建超大数据结构,如大数组。 - ...
Java NIO提供了两种Buffer类型:Heap Buffer和Direct Buffer。Heap Buffer在Java堆内存中创建,而Direct Buffer在操作系统堆外内存中创建,减少了系统调用的开销,适用于大容量数据传输。 6. **实战应用** - 文件...
【情况四】:`java.lang.OutOfMemoryError: Direct buffer memory` 这种情况发生在NIO(非阻塞I/O)中,因为直接缓冲区内存分配失败。可以通过设置`-XX:MaxDirectMemorySize`参数来限制直接内存大小,如`-XX:...
Heap Buffer存储在JVM堆中,而Direct Buffer则直接在操作系统分配的内存中,这使得它对内存管理的影响较小,对于大容量数据处理时,Direct Buffer通常能提供更好的性能,但会增加内存碎片的风险。 在实际应用中,...
2.2.7 Advice onSigned vs.Unsigned . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 2.3 Integer Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 ...
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); ``` 2. **非直接缓冲区**: 非直接缓冲区是在Java堆中分配的,数据传输需要经过JVM堆。虽然它没有直接缓冲区那么高效,但在处理小数据量时,由于...
8. Java.lang.OutOfMemoryError: Direct Buffer 错误 * 原因分析:直接缓冲区的内存不足 * 解决方案:增加直接缓冲区的内存大小、检查直接缓冲区的使用情况、优化直接缓冲区的使用 9. Java.lang.OutOfMemoryError:...
3. OutOfMemoryError: Direct buffer memory:堆外内存。 4. OutOfMemoryError: unable to create new native thread:无法创建新 native 线程。 解决方案: * 通过 -XX:MaxMetaspaceSize=512m 等 JVM 参数调整 ...
7. **零拷贝(Zero-Copy)**:Netty通过DirectBuffer和FileRegion实现零拷贝技术,减少了数据在内存中的复制,提高了性能。 8. **ChannelFuture和Promise**:ChannelFuture表示异步操作的结果,而Promise则用于设置...
- **Heap Buffer**:堆缓冲区则是在Java堆上分配的内存。 #### Channel Channel是Java NIO中的另一个核心概念,它类似于传统的流(Stream),但功能更加强大。Channel提供了一种从文件系统、网络或其他来源传输...
- 内存管理:DirectBuffer与HeapBuffer的选择 - 零拷贝技术:FileRegion和ByteBuf的使用 - 线程模型优化:EventLoopGroup的配置 - 长连接管理:心跳检测和超时策略 6. **Netty实战应用** - 构建Web服务器和...
JVM内存主要分为两大块:Java堆内存和直接内存映射(DirectBuffer占用)。推荐配置如下: - **堆内存**: 建议保持适中大小,例如在一个拥有16GB内存的服务器上,可以将Mycat的堆内存设置为4GB。 - **直接内存映射**...
如果直接内存过大,也会导致`java.lang.OutOfMemoryError: Direct buffer memory`。可以通过设置-Dsun.nio.ch maks.directBufferCount和-Djnio-direct-buffer-size来限制直接内存。 解决Java内存溢出问题通常需要...
本篇将详细探讨如何利用Direct3D12实现动态资源,特别是通过使用环形缓冲区(Ring Buffer)技术。 动态资源在3D渲染中指的是频繁更新或改变的数据,如顶点、索引缓冲区以及纹理数据。这些资源需要高效地在GPU之间...