`

java的DirectBuffer源码分析(主要是DirectBuffer的资源分配和回收)

    博客分类:
  • java
阅读更多
可以看到淘宝的一个说明:http://www.tbdata.org/archives/801

Java 2 SE 6 doc :

Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer’s content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system’s native I/O operations.

DirectBuffer通过免去中间交换的内存拷贝, 提升IO处理速度;

Java 2 SE 6 doc :

The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious.

DirectBuffer在-XX:MaxDirectMemorySize=xxM大小限制下[1], 使用Heap之外的内存, GC对此”无能为力”[2] ,也就意味着规避了在高负载下频繁的GC过程对应用线程的中断影响.
因此, 当系统应用场景满足:


大量原生类型数据使用
频繁IO操作
系统处理响应速度要求快且稳定
典型场景是网络数据传输, 可考虑合理应用DirectBuffer.


那么,DirectBuffer是怎么实现这些的呢:
DirectByteBuffer(int paramInt)
  {
    super(-1, 0, paramInt, paramInt, false);
    Bits.reserveMemory(paramInt);
    int i = Bits.pageSize();
    long l = 0L;
    try
    {
      l = unsafe.allocateMemory(paramInt + i); //这个是分配内存
    }
    catch (OutOfMemoryError localOutOfMemoryError)
    {
      Bits.unreserveMemory(paramInt);
      throw localOutOfMemoryError;
    }
    unsafe.setMemory(l, paramInt + i, 0);
    if (l % i != 0L)
      this.address = (l + i - (l & i - 1));
    else
      this.address = l;
    this.cleaner = Cleaner.create(this, new Deallocator(l, paramInt, null));//这个是负责回收资源。
    this.viewedBuffer = null;
  }



public native long allocateMemory(long paramLong);

allocateMemory 是一个本地方法,功能就是做一些参数检查和字节对齐,然后使用系统调用 malloc 申请一块内存。

从上面的分析也可以看出,创建一个 DirectByteBuffer 对象代价还是很大的,因为 malloc 系统调用代价就很大,需要 60 ~ 100 条 CPU 指令(一个 new Object() 只需要不足 10 条机器指令)。

注意,这个是操作系统直接分配的内存,java的垃圾回收是管不了的。


那是如何实现资源回收的呢。
 this.cleaner = Cleaner.create(this, new Deallocator(l, paramInt, null));

cleaner 的类型是Cleaner,Cleaner是PhantomReference(俗称的幽灵引用)的子类。当整个对象被回收的时候,幽灵引用会被java的虚拟机加到一个队列里去,ReferenceQueue。Reference有一个静态内部类ReferenceHandler。
 private static class ReferenceHandler extends Thread

然后还有个静态代码块:

 static
  {
    Object localObject1 = Thread.currentThread().getThreadGroup();
    for (Object localObject2 = localObject1; localObject2 != null; localObject2 = ((ThreadGroup)localObject1).getParent())
      localObject1 = localObject2;
    localObject2 = new ReferenceHandler((ThreadGroup)localObject1, "Reference Handler");
    ((Thread)localObject2).setPriority(10);
    ((Thread)localObject2).setDaemon(true);
    ((Thread)localObject2).start();
  }


也就是说虚拟机已启动,ReferenceHandler 这个线程就启动了,那ReferenceHandler 会做什么呢
public void run() {
	    for (;;) {

		Reference r;
		synchronized (lock) {
		    if (pending != null) {
			r = pending;
			Reference rn = r.next;
			pending = (rn == r) ? null : rn;
			r.next = r;
		    } else {
			try {
			    lock.wait();
			} catch (InterruptedException x) { }
			continue;
		    }
		}

		// Fast path for cleaners
		if (r instanceof Cleaner) {
		    ((Cleaner)r).clean();
		    continue;
		}

		ReferenceQueue q = r.queue;
		if (q != ReferenceQueue.NULL) q.enqueue(r);
	    }
	}
    }


可以看到其中有:
if (r instanceof Cleaner) {
		    ((Cleaner)r).clean();
		    continue;
		}

就是会执行幽灵引用的clean方法。

在clean方法执行的其实是:
 this.thunk.run();

thunk是在构造方法传进去的。对于DirectByteBuffer来说,他的thunk是Deallocator:
this.cleaner = Cleaner.create(this, new Deallocator(l, paramInt, null))


Deallocator的run方法会做什么事情呢:
public void run() {
	    if (address == 0) {
		// Paranoia
		return;
	    }
	    unsafe.freeMemory(address);
	    address = 0;
	    Bits.unreserveMemory(capacity);
	}


  public native void freeMemory(long paramLong);


可以看到这个也是个native方法。这里就会把资源回收。


有些人问为什么不用finalize去做资源回收,搞个幽灵索引,搞怎么麻烦。主要是因为java的
finalize不是很安全。如果finalize再搞一个对象本身的强引用,那么这个对象就永远不会回收掉了。但是幽灵引用不一样,幽灵引用起作用在对象的finalize之后,也就是说这个对象这个时候已经回收了。这样会更安全。
7
2
分享到:
评论
5 楼 shuizhaosi888 2015-03-19  
解决我一个大问题  
4 楼 lazy_ 2013-04-17  
huangyunbin 写道


我想请问一下,这是否意味这directBuffer可以不受HEAP大小控制?例如JVM最大2G,堆分了1.5G,那么MaxDirectMemorySize最大可以是多少呢?

我的观点是:directBuffer的使用内存已经和jvm没有关系了,他的限制是操作系统或者硬件的限制了。


我们在32位机器的前提上讨论吧。一个进程4G空间,2G内核,2G用户。你的意思好像是,DIRECT BYTE BUFFER 用的是2G内核空间里面的空间。我的理解对吗?
3 楼 huangyunbin 2013-04-17  


我想请问一下,这是否意味这directBuffer可以不受HEAP大小控制?例如JVM最大2G,堆分了1.5G,那么MaxDirectMemorySize最大可以是多少呢?

我的观点是:directBuffer的使用内存已经和jvm没有关系了,他的限制是操作系统或者硬件的限制了。
2 楼 lazy_ 2013-04-17  
引用
DirectBuffer在-XX:MaxDirectMemorySize=xxM大小限制下[1], 使用Heap之外的内存, GC对此”无能为力”[2] ,也就意味着规避了在高负载下频繁的GC过程对应用线程的中断影响.


我想请问一下,这是否意味这directBuffer可以不受HEAP大小控制?例如JVM最大2G,堆分了1.5G,那么MaxDirectMemorySize最大可以是多少呢?
1 楼 mtsw2011 2013-04-17  
   

相关推荐

    java源码包2

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    java远程监控源码

    标题“Java远程监控源码”涉及的是Java编程中关于远程监控和控制的实现。这个项目可能包含一个客户端(client)和服务器端(server)的架构,通过Socket通信进行数据交互,利用Java Robot类来捕获屏幕图像,以及...

    java管理系统源码

    Java管理系统的源码是开发者学习和理解企业级应用开发的重要资源。这些源码涵盖了不同的应用场景,包括学生信息管理、进销存控制、高校毕业就业分析以及图书管理,为我们提供了丰富的学习素材。以下将分别对这些管理...

    java源码:DataBuffer在Java中使用ADO.NET.rar

    【标题】:“DataBuffer在Java中使用ADO.NET”的源码分析 【描述】:这个压缩包包含了一组Java源码,展示了如何在Java环境中利用ADO.NET技术处理数据缓冲区(DataBuffer)。通常,ADO.NET是.NET框架中的一个数据库...

    java源码包3

     Java 3DMenu 界面源码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资源都有,都在压缩包内。 Java zip压缩包查看程序源码 1个目标文件 摘要:Java...

    JAVA源码DataBuffer在Java中使用ADO.NET

    JAVA源码DataBuffer在Java中使用ADO.NET

    java电子商务网站源码

    在分析和使用这套源码时,开发者需要对Java编程、Web开发框架、数据库管理和电子商务业务流程有深入理解。由于缺少Struts的jar包,开发者需要自行解决这个问题,或者选择使用其他框架进行重构。同时,对源码的充分...

    java 制作的企业网站源码

    java源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码源码...

    java 1.6 完整源码(包括 sun)

    Java 1.6,也被称为Java SE 6,...总结,Java 1.6的源码分析可以帮助我们深入了解Java平台的工作原理,学习和研究各种内部机制,同时"sun"包的探索则能让我们洞察Oracle JDK的实现细节,但需谨慎使用其中的非公开API。

    Flex+blazeds+java企业门户网站完整源码

    总之,这个“Flex+blazeds+java企业门户网站完整源码”是一个很好的学习资源,可以帮助开发者掌握如何利用Flex构建富用户体验的Web应用,并通过BlazeDS实现与Java后端的有效交互,进而构建高效、功能强大的企业级...

    129个Java项目源码下载

    这个"129个Java项目源码下载"集合提供了一个极好的学习资源,涵盖了各种类型的Java应用项目,帮助开发者深入理解Java编程的实际运用。 在Java项目开发中,我们通常会遇到多种技术栈和框架,例如Spring Boot用于构建...

    人力资源管理系统 java web 完整项目 包含源码和数据库

    权限管理通过角色和权限的分配,限制不同用户对资源的访问;日志记录有助于追踪操作历史,便于问题排查;异常处理则可以防止程序因意外情况崩溃,提高系统的健壮性。 总的来说,这个人力资源管理系统利用Java Web...

    java JDK7 官网源码 core

    Java JDK 7是Java开发工具包的一个重要版本,它包含了Java语言的...总的来说,这个Java JDK 7的核心源码压缩包对于Java开发者来说是一个宝贵的资源,它不仅可以深化对Java语言的理解,也有助于提升编程和问题解决能力。

    Java电商网站源码

    【Java电商网站源码】是一个基于Java编程语言的电子商务平台的源代码项目,它提供了构建电商网站所需要的核心功能和架构。这个源码项目确保了原始性、可用性和可靠性,为开发者提供了一个安心学习和开发的基础。 一...

    日历备忘录Java源码

    在本项目中,"日历备忘录Java源码" 提供了一套完整的日历应用程序的源代码,主要由四个核心文件组成:NotePad.java、CalendarPad.java、Month.java 和 Year.java。这些文件分别代表了备忘录、日历、月份和年份的功能...

    八套java web项目源码及视频讲解分享

    - **多参考优秀案例**:可以通过分析现有的Java Web项目源码,学习其中的设计模式和实现技巧。 - **参与社区交流**:加入相关的技术社区或论坛,与其他开发者交流经验,可以获得更多的灵感和技术支持。 通过以上对...

    java视频电影电视剧播放网站源码

    【标题】"java视频电影电视剧播放网站源码"所涉及的知识点主要集中在Java编程语言、Web开发、数据库设计以及多媒体内容的在线播放技术。这个标题表明我们正在讨论一个基于Java实现的在线影视平台,该平台能够播放...

    java JDK1.6.0源码 源代码

    Java JDK 1.6.0源码是Java开发者的重要参考资料,它揭示了JDK的核心类库是如何实现的,包括各种核心API和基础组件。对于深入理解Java语言、优化代码以及学习设计模式都有着不可估量的价值。 1. **Java类库**: - `...

    Java源码:比较经典的一些Java源代码,适合于初学者

    Java源码是学习编程语言的重要资源,特别是对于初学者来说,通过阅读和分析源代码,可以深入理解语言的特性和编程技巧。这个压缩包包含了140个经典的Java源代码程序,涵盖了各种基础到进阶的编程概念。下面,我们将...

    Java游戏源码集合(十一款,含Android)

    Java游戏源码集合包含了十一款游戏的源代码,这些源码是学习和研究Java编程以及游戏开发的宝贵资源。值得注意的是,其中有三个游戏已经被移植到了Android平台,这意味着这些源码不仅可以帮助我们理解Java桌面游戏的...

Global site tag (gtag.js) - Google Analytics