`
deepinmind
  • 浏览: 451528 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:41627
社区版块
存档分类
最新评论

Java中另类使用内存的方法

阅读更多
    sun.misc.Unsafe为你大开Java的方便之门,你可以用它做很多Java不允许的事情,在一些非常特殊的场景下它还是非常有用的。99%的时候,你都应该避免使用它,然而在有些非常罕见的情况下,只有它能解决问题。
本文讲述了它在OpenHFT中的使用场景以及我希望在Java 9中看到哪些功能。如果希望访问大量内存的同时又不影响GC,就特别适合使用Unsafe。在进程间共享内存,同时又不希望引起显著的开销,在Java中就只有这么一种方法了。

分配及释放堆内存

public native long allocateMemory();
public native void freeMemory(long address);


    你可以用这两个方法分配任何大小的堆内存。它不受Integer.MAX_VALUE字节的大小限制,返回给你的是原始内存,需要的话你可以进行边界检查。比如,Bytes.writeUTF(String)会计算编码的字符串的长度,检查是否容纳的下整个字符串,当然只做一次校验,不会每个字节都检查一遍。
java.lang里面也有一个类似的Cleaner类,DirectByteBuffer就用它来确保内存已经被释放了。不过这个类不太应该放到这么核心的地方。

访问原始内存
public native Xxx getXxx(Object, long offset); // intrinsic
public native void putXxx(Object, long offset);// intrinsic

在这两组方法中,当访问的是堆外的内存时,Object是为空的,offset就是实际的地址。在把它们当作内部函数的JVM上,你可以只用一条机器指令就可以访问原始内存。这极大的提高了内存访问的效率。
这种访问方式的问题就是,你得自己去维护你数据结构里面各个字段的分布。java.lang库里的解决办法是,它让你定义getter和setter方法,然后它在运行时生成具体的实现。也就是说,不管对象是堆内还是堆外的,你就直接通过getter和setter来访问它们就好了。

线程安全地访问内存
public native Xxx getVolatileXxx(Object, long offset); // intrinsic
public native void putOrderedXxx(Object, long offset); // intrinsic

有了这两组方法,你可以通过一个懒加载的集合来把一个字段模拟成volatile类型的。线程通过这个集合来设置值速度会更快,不过如果这个线程很快又读取值的话可能会读到旧的值。解决方法就是不要去读刚写完的值。
在进程中共享内存时,这两组方法尤其管用。

CAS操作
public native boolean compareAndSwapXxxx(Object, long offset, Xxx expected, Xxx setTo)

想创建一个堆外的锁,这组方法是少不了的。在进程间安全的共享数据的话,这也是最高效的一种方式。从我在Haswell处理器i7-4500上做的测试来看,同一机器上的两个进程间的通讯往返延迟的表现相当不错;
<table summary="日志级别">
    <tbody>
        <tr>
            <td>TCP</td>
            <td>- 9 micro-seconds.</td>
        </tr>
        <tr>
            <td>FileLocks</td>
            <td>- 5.5 micro-seconds.</td>
        </tr>
        <tr>
            <td>CAS</td>
            <td>- 0.12 micro-seconds.</td>
        </tr>
        <tr>
            <td>Ordered write</td>
            <td>- 0.02 micro-seconds.</td>
        </tr>
    </tbody>
</table>
堆对象的分配
public native Object allocateInstance(Class clazz);

当类反序列时,你当然希望类里面的值会恢复成序列前的样子。不过在现在的构造方法中,这个可能会有点小问题,JEP 187: Serialization 2.0中有提到过这个问题。一个解决方法就是彻底不使用构造方法来创建新对象。这说明你得充分信任你的数据正确性,好处就是它易于使用且不用关心到底用哪个构造方法来实例化对象。

结论
嵌入式的数据库由于没有额外的网络开销,在请求延迟方面是远优于分布式数据库的。我相信下一代低延迟的数据库不但能达到嵌入式数据库的性能,还能在进程间进行共享,同时它的更新和查询的响应时间都能在毫秒级以下。

Java没理由会不去实现它。对Java用户而言,本地接口的性能是最佳的,因为它不需要JNI,或者说是不需要进行Java和C之间的一层转化。

译者注:文章假定读者对Unsafe有一定的了解和认识,更详细的说明请关注deepinmind或本博客的后续文章
文章同时发表于本人博客:deepinmind

更多文章请关注:Java译站


2
4
分享到:
评论

相关推荐

    java基本组件使用

    在Java世界中,这些基本组件主要包括JVM(Java虚拟机)、类库、API(应用程序接口)以及开发工具等。下面我们将详细探讨这些组件以及它们在实际开发中的应用。 1. JVM(Java Virtual Machine) JVM是Java平台的...

    一个内存流的合并添加删除读出输出的类(含DEMO)

    内存流是一种基于内存的数据流,它允许程序在内存中创建临时数据流,以便快速地进行数据传输和处理。在Java中,`java.io.ByteArrayInputStream`和`java.io.ByteArrayOutputStream`是常见的内存流类;而在C#中,`...

    《Java2核心技术卷II》配套源码

    1. **多线程编程**:Java2核心技术卷II中详细介绍了如何在Java中实现多线程,包括Thread类和Runnable接口的使用、同步机制(synchronized关键字,wait(),notify(),notifyAll()方法)、线程池(ExecutorService,...

    164个完整的Java程序源代码

    18. **性能优化**:观察代码中如何实现性能优化,例如内存管理、算法选择等。 19. **测试**:了解如何编写单元测试,使用JUnit或其他测试框架。 【标签】"另类其它 控件 源码 资源"提示了这些源代码可能包含了一些...

    大公司JAVA面试试题

    - 了解堆和栈内存的区别,以及对象在内存中的分配。 - 熟悉Java的垃圾回收机制,包括引用类型(强、软、弱、虚引用)及其作用。 - 掌握JVM内存模型(堆、方法区、栈、本地方法栈、程序计数器)。 3. **集合框架*...

    《Java中间件技术及其应用开发》-李华飚-源代码

    10. **Redis**:Redis是一个内存中的数据结构存储系统,可用作数据库、缓存和消息中间件,以提高数据访问速度。 书中的源代码可能涉及以上这些中间件技术的具体实现和应用场景,通过阅读和理解这些代码,读者可以...

    sqlite另类存取(对象存取)

    在常规操作中,我们通常使用SQL语句来存取数据,但有时为了更方便地管理和操作复杂的数据结构,比如对象,我们会采取一些“另类存取”方式,如将Java对象序列化后存储在SQLite数据库中。这篇描述提到了一种这样的...

    《JAVA 应用开发详解》代码

    在Java中,可以使用不同的API来读取、写入文件,管理内存中的资源,或者与数据库、网络服务进行通信。这部分内容对于开发实际项目非常实用。 压缩包"CODE"中,很可能包含了书中各个章节的示例代码,按照章节组织,...

    《精通JAVA核心技术》 源代码

    源代码将展示如何在类、接口、方法和集合中使用泛型,以及它们带来的优势。 9. **枚举与注解**:Java枚举提供了一种安全的常量表示方式,而注解则是一种元数据,可以用来提供编译时或运行时的信息。源代码将包含这...

    KJAVA大赛DemoCode

    这个压缩包包含了参赛者提交的一些演示程序,旨在展示在移动设备上使用Java ME进行开发的各种技术和技巧。Java ME是Java平台的一个轻量级版本,主要用于嵌入式系统,包括手机和移动设备。 【MIDP_GUI】目录可能包含...

    Java切割机

    在提供的文件列表中,我们看到有"说明.htm",这通常是一个包含软件使用指南或详细功能介绍的HTML文档,用户可以通过阅读这份文档了解如何使用Java切割机,包括其命令行参数、方法调用等。"代码中国.txt"可能包含了...

    另类过主动防御系统代码.7z

    2. **代码注入**:代码注入是将恶意代码放入另一个正在运行的进程内存空间中的过程,使目标进程执行攻击者指定的行为。常见的注入技术包括CreateRemoteThread、WriteProcessMemory等API,以及利用DLL注入和反射DLL...

    使用集束搜索(beam search)方法的图搜索算法

    7. **性能优化**:为了提高效率,可以采用剪枝策略,如回溯过程中删除无望达到目标的分支,或者使用记忆化技术避免重复计算。 8. **源码结构**:`GraphSearch`文件夹中可能包含了主程序类、节点类、队列类以及其他...

    jspsmartupload组件源码

    - **SmartRequest.java**: 这是对HttpServletRequest的封装,提供了处理上传请求的便捷方法,能够解析请求中的多部分数据。 - **SmartFiles.java**: 是一个SmartFile对象的集合,用于存储多个上传文件,方便进行...

    JPorofiler

    Profiler是一个商业授权的Java剖析工具...它允许两个内存剖面评估内存使用情况和动态分配泄漏和CPU剖析,以评估线程冲突。JProfiler直觉式的GUI让你可以找到性能瓶颈、抓出内存漏失(memory leaks)、并解决执行绪的问题

    Java下XML的解析

    如果使用:JAXB(Java ArchitectureforXMLBinding),个人觉得太方便了!:个人理解类似.net的XmlDocument,解析的时候效率不高,占用内存,不适合大XML的解析;:基于事件的解析,当解析到xml的某个部分的时候,会...

    JDBC入门中文文档

    **JDBC(Java Database ...了解并熟练掌握JDBC的基本概念和使用方法,是每个Java开发者必备的技能之一。通过阅读“JDBC入门中文文档”,你可以深入理解这些知识,从而在实际项目中高效地使用JDBC进行数据库操作。

    SCJP认证考试资料

    Java中的异常处理机制是另一个重要的考点,考生需要掌握try-catch-finally语句块的使用,理解不同类型的异常(checked和unchecked),以及如何自定义异常。 四、内存管理 Java的垃圾回收机制是其与传统C++等语言的...

    函数式编程另类指南.pdf

    ### 函数式编程另类指南知识点解析 #### 一、函数式编程简介 **函数式编程**是一种编程范式,它将计算过程视为一系列函数调用。与传统的命令式编程不同,函数式编程强调不可变性和纯函数的概念,即函数的结果只...

    一个开源的JVM

    5. **垃圾收集**:自动管理内存,释放不再使用的对象,防止内存泄漏。 6. **本地方法接口**:允许JVM调用非Java代码,如操作系统API,提供与平台交互的能力。 7. **源码分析**:开源JVM的源码提供了学习Java虚拟机...

Global site tag (gtag.js) - Google Analytics