byte buffer一般在网络交互过程中java使用得比较多,尤其是以NIO的框架中;
看名字就知道是以字节码作为缓冲的,先buffer一段,然后flush到终端。
而本文要说的一个重点就是HeapByteBuffer与DirectByteBuffer,以及如何合理使用DirectByteBuffer。
1、HeapByteBuffer与DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap区域的,其实真正flush到远程的时候会先拷贝得到直接内存,再做下一步操作(考虑细节还会到OS级别的内核区直接内存),其实发送静态文件最快速的方法是通过OS级别的send_file,只会经过OS一个内核拷贝,而不会来回拷贝;在NIO的框架下,很多框架会采用DirectByteBuffer来操作,这样分配的内存不再是在java heap上,而是在C heap上,经过性能测试,可以得到非常快速的网络交互,在大量的网络交互下,一般速度会比HeapByteBuffer要快速好几倍。
最基本的情况下
分配HeapByteBuffer的方法是:
- ByteBuffer.allocate(int capacity);参数大小为字节的数量
ByteBuffer.allocate(int capacity);参数大小为字节的数量
分配DirectByteBuffer的方法是:
- ByteBuffer.allocateDirect(int capacity);//可以看到分配内存是通过unsafe.allocateMemory()来实现的,这个unsafe默认情况下java代码是没有能力可以调用到的,不过你可以通过反射的手段得到实例进而做操作,当然你需要保证的是程序的稳定性,既然叫unsafe的,就是告诉你这不是安全的,其实并不是不安全,而是交给程序员来操作,它可能会因为程序员的能力而导致不安全,而并非它本身不安全。
ByteBuffer.allocateDirect(int capacity);//可以看到分配内存是通过unsafe.allocateMemory()来实现的,这个unsafe默认情况下java代码是没有能力可以调用到的,不过你可以通过反射的手段得到实例进而做操作,当然你需要保证的是程序的稳定性,既然叫unsafe的,就是告诉你这不是安全的,其实并不是不安全,而是交给程序员来操作,它可能会因为程序员的能力而导致不安全,而并非它本身不安全。
由于HeapByteBuffer和DirectByteBuffer类都是default类型的,所以你无法字节访问到,你只能通过ByteBuffer间接访问到它,因为JVM不想让你访问到它,对了,JVM不想让你访问到它肯定就有它不可告人的秘密;后面我们来跟踪下他的秘密吧。
2、前面说到了,这块区域不是在java heap上,那么这块内存的大小是多少呢?默认是一般是64M,可以通过参数:-XX:MaxDirectMemorySize来控制,你够牛的话,还可以用代码控制,呵呵,这里就不多说了。
3、直接内存好,我们为啥不都用直接内存?请注意,这个直接内存的释放并不是由你控制的,而是由full gc来控制的,直接内存会自己检测情况而调用system.gc(),但是如果参数中使用了DisableExplicitGC 那么这是个坑了,所以啊,这玩意,设置不设置都是一个坑坑,所以java的优化有没有绝对的,只有针对实际情况的,针对实际情况需要对系统做一些拆分做不同的优化。
4、那么full gc不触发,我想自己释放这部分内存有方法吗?可以的,在这里没有什么是不可以的,呵呵!私有属性我们都任意玩他,还有什么不可以玩的;我们看看它的源码中DirectByteBuffer发现有一个:Cleaner,貌似是用来搞资源回收的,经过查证,的确是,而且又看到这个对象是sun.misc开头的了,此时既惊喜又郁闷,呵呵,只要我能拿到它,我就能有希望消灭掉了;下面第五步我们来做个试验。
5、因为我们的代码全是私有的,所以我要访问它不能直接访问,我需要通过反射来实现,OK,我知道要调用cleaner()方法来获取它Cleaner对象,进而通过该对象,执行clean方法;(付:以下代码大部分也取自网络上的一篇copy无数次的代码,但是那个代码是有问题的,有问题的部分,我将用红色标识出来,如果没有哪条代码是无法运行的)
- import java.nio.ByteBuffer;
- import sun.nio.ch.DirectBuffer;
- public class DirectByteBufferCleaner {
- public static void clean(final ByteBuffer byteBuffer) {
- if (byteBuffer.isDirect()) {
- ((DirectBuffer)byteBuffer).cleaner().clean();
- }
- }
- }
import java.nio.ByteBuffer; import sun.nio.ch.DirectBuffer; public class DirectByteBufferCleaner { public static void clean(final ByteBuffer byteBuffer) { if (byteBuffer.isDirect()) { ((DirectBuffer)byteBuffer).cleaner().clean(); } } }
上述类你可以在任何位置建立都可以,这里多谢一楼的回复,以前我的写法是见到DirectByteBuffer类是Default类型的,因此这个类无法直接引用到,是通过反射去找到cleaner的实例,进而调用内部的clean方法,那样做麻烦了,其实并不需要那么麻烦,因为DirectByteBuffer implements了DirectBuffer,而DirectBuffer本身是public的,所以通过接口去调用内部的Clear对象来做clean方法。
我们下面来做测试来证明这个程序是有效地回收的:
在任意一个地方写一段main方法来调用,我这里就直接写在这个类里面了:
- public static void sleep(long i) {
- try {
- Thread.sleep(i);
- }catch(Exception e) {
- /*skip*/
- }
- }
- public static void main(String []args) throws Exception {
- ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 100);
- System.out.println("start");
- sleep(10000);
- clean(buffer);
- System.out.println("end");
- sleep(10000);
- }
public static void sleep(long i) { try { Thread.sleep(i); }catch(Exception e) { /*skip*/ } } public static void main(String []args) throws Exception { ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 100); System.out.println("start"); sleep(10000); clean(buffer); System.out.println("end"); sleep(10000); }
这里分配了100M内存,为了将结果看清楚,在执行前,执行后分别看看延迟10s,当然你可以根据你的要求自己改改。请提前将OS的资源管理器打开,看看当前使用的内存是多少,如果你是linux当然是看看free或者用top等命令来看;本地程序我是用windows完成,在运行前机器的内存如下图所示:
开始运行在输入start后,但是未输出end前,内存直接上升将近100m。
在输入end后发现内存立即降低到2.47m,说明回收是有效的。
此时可以观察JVM堆的内存,不会有太多的变化,注意:JVM本身启动后也有一些内存开销,所以不要将那个开销和这个绑定在一起;这里之所以一次性申请100m也是为了看清楚过程,其余的可以做实验玩玩了。
相关推荐
在Java编程中,获取计算机硬件信息,如CPU、主板和硬盘序列号,通常是通过操作系统提供的API接口或者第三方库来实现的。以下是一个详细的步骤和知识点介绍: 1. **CPU序列号获取**: CPU序列号是CPU的一个唯一标识...
高吞吐低延迟Java应用的垃圾回收优化 高吞吐低延迟Java应用的垃圾回收优化 高吞吐低延迟Java应用的垃圾回收优化 高吞吐低延迟Java应用的垃圾回收优化 高吞吐低延迟Java应用的垃圾回收优化 高吞吐低延迟Java应用的...
Java垃圾回收机制详解和调优.doc Java垃圾回收机制详解和调优.doc Java垃圾回收机制详解和调优.doc Java垃圾回收机制详解和调优.doc Java垃圾回收机制详解和调优.doc Java垃圾回收机制详解和调优.doc Java垃圾回收...
Azul Systems CTO & co-Founder, Gil Tene 在SpringOne2GX 2012大会上发表的演讲资料,全面深入地阐述Java垃圾回收的四种机制。并介绍了当今世界上性能与吞吐量最高的JVM产品Zing JVM。 如果希望深入了解Java的垃圾...
java某百货店POS积分管理系统_积分点更新生成以及通票回收处理(源代码+论文)java某百货店POS积分管理系统_积分点更新生成以及通票回收处理(源代码+论文)java某百货店POS积分管理系统_积分点更新生成以及通票回收处理...
Thinking in C: Foundations for Java & C++ by Chuck Allison produced by Bruce Eckel Chapter 1: Introduction and Getting Started40 MinutesStart Lecture Chapter 2: Fundamental Data Types41 ...
java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。 java.lang.ref 提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。 java.lang.reflect 提供类...
- **简单性**:Java简化了C++的一些复杂特性,如没有指针,自动垃圾回收,以及对多继承的限制,这使得代码更易读、更安全。 - **面向对象**:Java完全支持面向对象编程,包括类、接口、封装、继承和多态等概念。它...
Java is a popular and powerful language that is a virtual requirement for businesses making use of IT in their daily operations For Java programmers this reality offers job security and a wealth of ...
Java NIO(New IO)是Java 1.4版本引入的一种新的IO API,用来替代标准的Java IO API。NIO提供了非阻塞的I/O操作,可以提高在处理多个连接时的性能。Netty是一个高性能、异步事件驱动的网络应用框架,用于快速开发可...
### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....
用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及源代码 1个目标文件 摘要:Java源码,初学实例,波浪文字 Java波浪文字,一个利用...
Java2Pas是一个实用工具,主要用于将Java编程语言编写的源代码转换为Pascal语言的等效代码。这个工具对于那些需要在两种语言之间迁移代码或者理解不同编程语言语法的开发者来说非常有价值。Java和Pascal虽然都是面向...
Java是最流行的编程语言之一,在软件开发行业中非常常用。以下是Java笔试题汇总,涵盖了Java的多个方面,包括Java基础、Java面向对象编程、Java多线程、Java网络编程、Java数据库编程等。 Java基础 1. Java的基本...
这是一本以面试题为入口讲解 Java 核心内容的技术书籍,书中内容极力的向你证实代码是对数学逻辑的具体实现。当你仔细阅读书籍时,会发现Java中有大量的数学知识,包括:扰动函数、负载因子、拉链寻址、开放寻址、...
1. **Java网络编程基础**:首先,书中会介绍Java中的Socket编程,包括TCP和UDP协议的基础知识,以及如何使用Java的Socket和ServerSocket类创建客户端和服务器端的连接。 2. **I/O与NIO**:Java的I/O流系统是网络...
Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建对象、获取类...
安装过程中,它会自动配置Java开发环境变量,包括JAVA_HOME、PATH以及CLASSPATH,以便系统能够识别并执行Java命令。此外,它还包含JRE(Java Runtime Environment),使得开发者机器上能够运行Java应用程序。 对于...
总之,Java Runtime Environment JRE 1.4.2是Java平台历史上的一个重要版本,它的性能优化、安全增强以及API的丰富性,都为开发者提供了更强大的工具,同时也为用户提供了稳定且高效的运行环境。尽管随着Java技术的...