`

Java ByteBuffer 之 DirectBuffer

    博客分类:
  • java
 
阅读更多

ByteBuffer 提供了两种方式创建缓冲区,一个是在heap内分配即DirectBuffer,一个是在heap外分配。一个比较普遍的说法是,heap外分配的内存不太好把控,JVM不会回收其内存。然而事实上真的如此吗?我做了一个实验,我写了一个NIO服务端程序不断读取客户端发送过来的内容,然后回写到客户端。回写的时候用了DirectBuffer, 并且开辟的内存故意设的比较大128M。请看如下服务器代码片段。

 

    /** 
     * 处理读取客户端发来的信息 的事件 
     * @param key 
     * @throws IOException  
     */  
    public void read(SelectionKey key) throws IOException{  
        // 服务器可读取消息:得到事件发生的Socket通道  
        SocketChannel channel = (SocketChannel) key.channel();  
        // 创建读取的缓冲区  
      ByteBuffer buffer = ByteBuffer.allocate(256); 
       // ByteBuffer buffer =ByteBuffer.allocateDirect(1024*1024);
        channel.read(buffer);  
        byte[] data = buffer.array();  
        String msg = new String(data).trim();  
        System.out.println("服务端收到信息:"+msg);  
        //ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); 
        ByteBuffer buffer2 =ByteBuffer.allocateDirect(1024*1024*128);
        buffer2.put(msg.getBytes());
        channel.write(buffer2);// 将消息回送给客户端
        System.out.println(buffer2.getClass().getName());
    
    }  
 

 运行服务端程序后我们观察内存变化情况。我们先看看程序运行前CPU跟内存情况。




如红色标记出来的片段显示,内存非常平稳,cpu也几乎闲着。运行代码后,我们再观察

 
 


 
 观察发现内存有了波动,但是基本稳定在2.91GB,比运行前增加的内存与direct buffer分配的内存大致相当。每次在内存波动比较大的情况下,CPU都有个冲浪,然后内存又被压下来,说明在回收内存,而并没有出现内存泄漏。因此JVM会做DirectBuffer的垃圾回收。

如果对JVM不放心,那我们可自己回收吗? 答案也是 "Big Yes"

我将代码增加清除的逻辑,并在分配内存之后睡眠10秒,然后再清除方便观察内存情况。发现分配后内存每次都会增加,但是清除之后立马内存就降下来了,请看代码不再贴图。有人会觉得奇怪这里为什么用反射去调用方法,原因是不同jre返回的class不一样,但是都提供了clean方法。

public void read(SelectionKey key) throws IOException{  
        // 服务器可读取消息:得到事件发生的Socket通道  
        SocketChannel channel = (SocketChannel) key.channel();  
        // 创建读取的缓冲区  
      ByteBuffer buffer = ByteBuffer.allocate(256); 
       // ByteBuffer buffer =ByteBuffer.allocateDirect(1024*1024);
        channel.read(buffer);  
        byte[] data = buffer.array();  
        String msg = new String(data).trim();  
        System.out.println("服务端收到信息:"+msg);  
        //ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes()); 
        ByteBuffer buffer2 =ByteBuffer.allocateDirect(1024*1024*128);
        buffer2.put(msg.getBytes());
        channel.write(buffer2);// 将消息回送给客户端
   
        clean(buffer);
    
    }  
 
    public void clean(ByteBuffer buffer){
        try {
        	System.out.println("buffer已分配,睡10秒钟,请注意观察内存变化,,,");
    			Thread.sleep(10000);
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
			try {
				 Method cleanerMethod = buffer.getClass().getMethod("cleaner");
				  cleanerMethod.setAccessible(true);
				  Object cleaner = cleanerMethod.invoke(buffer);
				  Method cleanMethod = cleaner.getClass().getMethod("clean");
				  cleanMethod.setAccessible(true);
				  cleanMethod.invoke(cleaner);
	    			Thread.sleep(3000);

			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

    }

 

既然DirectBuffer效率也高,回收也没问题,那为何不用DirectBuffer呢? 答案是,DirectBuffer的创建跟回收会比Heap的开销大,对于字节数不多的通信,两者甚至heap的缓冲效率略高,如果DirectBuffer会持续长时间或者会被重用,那用DirectBuffer会是不错的选择。因此说大文件的传输用DirectBuffer是比较合适的。

  • 大小: 14.6 KB
  • 大小: 11.5 KB
分享到:
评论

相关推荐

    Java中的缓冲区(直接缓冲区、非直接缓冲区等).docx

    ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); ``` 2. **非直接缓冲区**: 非直接缓冲区是在Java堆中分配的,数据传输需要经过JVM堆。虽然它没有直接缓冲区那么高效,但在处理小数据量时,由于...

    缓冲池 java

    Heap Buffer存储在Java堆中,而Direct Buffer存储在系统内存中,直接与硬件交互,减少了Java虚拟机(JVM)的内存拷贝,提高了性能。然而,Direct Buffer可能会占用更多的系统资源,因此在选择时需要权衡性能和资源...

    Java-NIO-Programming-Cookbook(含源码)

    `DirectByteBuffer`是`ByteBuffer`的一个实现,它与`Non-Direct Buffer`(即堆缓冲区)有所不同。直接缓冲区在Java中使用JNI(Java Native Interface)直接在物理内存中分配,而不需要经过Java堆,这通常能提高性能...

    Java Nio ibm技术文档

    ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); ``` #### 六、总结 本文档通过对NIO库的详细介绍,旨在帮助Java开发者更好地理解和掌握NIO的核心概念和技术细节。通过学习缓冲区、通道和选择器等关键...

    学习笔记 java\CoreJava笔记\CoreJava_day21

    ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); ``` #### 三、`FileChannel`详解 ##### 1. 概念 `FileChannel`是NIO中的一个接口,它提供了对文件的读写操作,可以看作是对`FileInputStream`和`...

    java代码-buffer

    Java NIO提供了两种Buffer类型:Heap Buffer和Direct Buffer。Heap Buffer在Java堆内存中创建,而Direct Buffer在操作系统堆外内存中创建,减少了系统调用的开销,适用于大容量数据传输。 6. **实战应用** - 文件...

    Java_NIO_API详解

    1. **`java.nio`**: 定义了各种类型的缓冲区(Buffer),包括`ByteBuffer`、`CharBuffer`等。 2. **`java.nio.channels`**: 提供了一系列通道(Channel)接口及其具体实现,支持文件和网络的I/O操作。 3. **`java.nio....

    java netty权威指南完整版带目录

    - 零拷贝技术:Netty利用DirectBuffer和FileRegion实现数据传输中的零拷贝,减少了CPU的负担。 - ByteBuf的缓冲区操作:通过HeapByteBuf和DirectByteBuf实现内存优化。 7. **Netty的性能优化** - 管道优化:合理...

    Java堆外内存的使用Java开发Java经验技巧共5页

    - NIO Channel与Buffer:使用FileChannel的`map`方法映射文件到直接内存,或者使用ByteBuffer的`allocateDirect`创建直接内存缓冲区。 - JNI(Java Native Interface):通过JNI调用C/C++代码,分配和管理堆外内存...

    Netty那点事(1)概述Java开发Java经验技巧共5

    在性能优化方面,Netty提供了一套完整的内存管理机制,如DirectBuffer和ByteBuf,这些设计减少了系统间的内存拷贝,提高了效率。ByteBuf是一个高效且易用的字节缓冲区,相比Java NIO中的ByteBuffer,它更方便进行...

    JAVA IO-NIO 详解

    - **Direct vs Non-Direct Buffer**: Direct Buffer直接映射到物理内存,Non-Direct Buffer在JVM堆上分配内存。 **3. Buffer的日常操作** - **put**: 向Buffer写入数据。 - **get**: 从Buffer读取数据。 - **flip*...

    Netty-4.1.97.Final源码

    同时,Netty还使用了Direct Buffer,减少内存页在Java堆和操作系统之间的交换,进一步提高了性能。 在本地化修改场景下,你可以通过阅读源码理解Netty如何处理各种网络事件,如何优化性能,甚至可以根据项目需求...

    android opengl学习文档

    在OpenGL ES中,主要使用的是Buffer类来管理数据,它允许开发者以内存缓冲区的方式来处理大量的数据读写,并且可以避免Java垃圾回收机制的干扰,因为DirectBuffer可以直接从操作系统内存分配空间,这部分空间不会被...

    10道Java高级必备的Netty面试题!.zip

    - **FileRegion**和**DirectBuffer**:通过使用FileChannel的transferTo方法和DirectByteBuffer,实现了数据在操作系统级别上的零拷贝传输。 4. **Pipeline(处理链)** - **事件处理**:Pipeline由多个处理器...

    mina高性能Java网络框架 v2.0.23.zip

    6. **内存管理**:MINA使用DirectBuffer和ByteBuffer进行内存管理,减少了Java对象创建和垃圾收集的开销,提升了性能。 7. **API设计**:MINA的API设计简洁且易于使用,提供了丰富的接口和类,帮助开发者快速开发...

    java nio 详解

    NIO还支持直接缓冲区(Direct Buffer),这种缓冲区直接在本地内存中分配空间,避免了Java堆和本地内存之间的数据复制,从而提高了性能。 ##### 3. 异步I/O 除了非阻塞I/O外,NIO还支持异步I/O操作。在某些情况下...

    netty-code源码

    7. **零拷贝(Zero-Copy)**:Netty通过DirectBuffer和FileRegion实现零拷贝技术,减少了数据在内存中的复制,提高了性能。 8. **ChannelFuture和Promise**:ChannelFuture表示异步操作的结果,而Promise则用于设置...

Global site tag (gtag.js) - Google Analytics