使用Java堆外内存(自己管理内存)的一些方法

HugeCollections-OLD:使用高效堆外存储的 Java 巨大集合 SharedHashMap 已弃用 SharedHashMap 已重新设计并移至新 GitHub 项目下的 ChronicleMap SharedHashMap 的所有新开发都将在 ChronicleMap 项目上完成,旧的 ShareHashMap 代码将保留在这里,所有新的增强功能都将添加到 ChronicleMap 中。 如果您在生产中运行它并希望获得专业支持的代码,请参阅 巨大的收藏 使用高效堆外存储的 Java 巨大集合 HugeHashMap 支持并发访问非常大的堆外键/值对。 来自 HugeHashMapTest HugeConfig config = HugeConfig.DEFAULT.clone() .setSegments(128) .setSmallEntrySize(128) .setCapacity(cou 立即下载

背景

      使用Java的一大好处就是自动内存管理,程序员不用太关心内存的是否,JVM的Garbage Collector(GC)帮我们找到不被引用的垃圾对象并清除掉。但是有得必有失,我们也失去了自己管理内存的可能性。【个人观点:大多数程序员的内存管理水平都比不上JVM,虽然程序员可能更了解业务逻辑,知道某个对象已经死掉,可以回收。但是回收的内存什么时候应该compact,内存分配使用什么算法,这样不是简单的问题。所以如果不是逼不得已,最好的办法还是优化代码,优化JVM的GC参数】

      但是可能还是存在一些应用场景,如果能够自己管理内存的话,性能可能更优(或者说代码写得好的话可能更优)。比如一些非常简单的业务逻辑或者算法,需要使用大量内存,尤其是像Cache,会在内存里呆很久。但是如果放到堆里,那么会影响Full GC的Pause Time

问题

      但是Java的设计者并不允许我们这么做(可能设计者的理念是:一旦留了个后门,那么就会有各种“优化秘笈”,各种水平的程序员都会附庸风雅一番,结果导致更差的性能,然后就会得出结论:Java语言很差。这就像我们印象中的Firefox很慢,其实很大一部分原因可能是我们使用了憋足的插件,但是我们不会管那么多,我们只会把罪名归到Firefox身上)       

救星------ByteBuffer

      在NIO出现之前应该没有什么办法可以自己申请堆外内存,但是NIO为了高效,“不得不”提供了ByteBuffer。但是它还是把ByteBuffer纳入了管理的范畴,你没有办法显示“释放”ByteBuffer,就像你调用System.gc()不能保证调用GC一样,你只能祈祷上天保佑马上会有GC。不过如果不考虑JVM的移植和版本的升级,Sun的DirectBuffer接口提供了Cleaner对象(sun.misc.Cleaner)。这是有风险的,比如你不使用Sun或者OpenJDK,或者等到以后的某个JDK版本,这些方法可能木有了。我们使用的ByteBuffer.allocateDirect得到的就是DirectByteBuffer,它实现了DirectBuffer接口。

等等------问题还没解决

      给我一个ByteBuffer有什么用?我可以把它变成一个byte[]。那照样没有什么用,难道我必须这样修改代码?

class Person{
    long id;
    int age;
    boolean gender;

    public int getAge(){
       return age;
    }
    public void setAge(int age){
       this.age=age;
    }
    .....
}

class PersonWrapper{
    ByteBuffer buf;

    public int getAge(){//假设我们的内存布局是上面的顺序
        return buf.getInt(8);
    }
    public PersonWrapper(){
        buf=ByteBuffer.allocateDirect(13);
    }

    public free(){
        ((DirectBuffer) buffer).cleaner().clean();
    }
}

     这样的代码看起来很像c的malloc和free,但是尽量别这么用。这里有个问题就是我们只能使用原始类型,如果你使用了对象,那么还是在Heap里由GC管理。

     如果你真的这么写Java代码那么我建议你直接使用C/C++。我们使用Java很大一部分是使用Java的类库,包括JRE里语言规定的和各种第三方的。我们的代码需要使用它们提供的对象。我们需要传递参数给它,这些参数可能就是对象,返回值也是。

     当然如果你从头开始必须用Java实现一个基础模块,它不需要使用任何其它对象,那么也许你可以考虑这种方法。这种方法的对象回收有两种方式,一种就是显示调用free方法,像我们写c一样,另外就是不管它,等PersonWrapper被回收的适合,buf也自动变成垃圾了。但正如GC的不确定性,可能等到GC再回收的话,可能Heap+DirectMemory把内存都用爆了,甚至连JVM都没有内存做GC!!

      我们可能更喜欢使用Java的对象编码(虽然使用Wrapper的方法可能更节省空间),字节数组实在太难用了。解决这个问题有下面两种方法:

序列化/反序列化

      对于Cache这样的应用,我们可以把它存到堆外,写的时候把对象序列化成byte[],保存至DirectBuffer,使用时把byte[] 反序列化回来。这个方法的缺点是序列化和反序列化会消耗CPU,另外如果对象很大的话,使用时反序列化出来的对象还是会占用Heap空间。

      这种方法可以参考或者使用http://incubator.apache.org/directmemory/  这是一个Apache的孵化项目,使用风险自负,呵呵。

      淘宝的一些测试:http://rdc.taobao.com/team/jm/archives/1539

字节码修改

      和前面的wrapper类似,不过提供更友好的方式,自己少些那么多代码,不用记住某个字段的指针偏移。

      参考项目:https://code.google.com/p/vanilla-java/wiki/HugeCollections

      缺点,和wrapper一样,只能使用原生类型,如果使用对象,那么这个对象还是在堆里。因为我们不可能写所有的代码,比如要使用别人写好的对象。

      可能的解决办法和序列化类似,把需要用的对象拷贝到ByteBuffer,就像C++的拷贝构造函数,而不是传递指针或者引用。

有没有更好的解决办法?

      或许有,比如想淘宝他们自己修改定制JVM,当然这就完全修改了Java的语法,或者不能叫Java语言了。

      有兴趣的可以看看http://www.infoq.com/cn/presentations/ms-jvm-taobao 作者的博客:http://rednaxelafx.iteye.com/

结论 
      在某些特殊场景(比如没有任何办法能够优化GC的Pause Time了,老大还不让加机器,呵呵),而且业务相对简单,那么也许可以尝试一下。
一文入门Qwen-Agent【附实战代码】 Qwen-Agent 是一个开源框架,用于开发基于 Qwen 模型的 AI 智能体应用,一文带你入门使用 阅读详情

相关推荐

Cadence仿真MOS电容C-V曲线:从电路图到参数扫描的完整流程

本文详细介绍了使用Cadence Virtuoso仿真MOS电容C-V曲线的完整流程,从电路图绘制到参数扫描,再到结果分析与问题排查。通过实际案例和实用技巧,帮助工程师快速掌握MOS电容特性分析的关键步骤,提升集成电路设计效率。

weixin_29271263的博客 429

Java 堆外内存管理

目录 1.什么是堆外内存? 2.堆外内存有什么优势? 3.堆外内存的使用 3.1堆外内存的设置 3.2堆外内存的创建 3.3堆外内存的回收 3.3.1自动回收 3.3.2手动回收 1.什么是堆外内存? 堆外内存和堆内内存是两个相对的概念,其中堆内内存(on-heap memory)是我们平常工作中接触比较多的。Java中分配的非空对象都是由Java虚拟机的垃圾收集器管理的,都是...

时光钟摆 1327

IROS 2025机器人技术解析:从诡异设计到硬核应用

机器人技术正从传统的结构化环境应用,迈向复杂非结构化场景的深度交互。其核心原理在于通过仿生设计、多模态感知与智能控制算法,赋予机器人类似生物的适应性与交互能力。这一技术演进的价值在于突破传统机器人在极端环境、精密操作和自然交互中的瓶颈。例如,结合深度强化学习的全身动力学控制,使机器人能在废墟、管道等复杂地形中自主导航;而软体机器人技术则通过材料变形实现安全、柔顺的抓取操作。这些技术最终服务于极端环境巡检、精密装配和高端陪护等刚性应用场景,推动机器人从功能实现迈向与环境、人进行深度、智能交互的新阶段。

weixin_34006468的博客 448

Java 堆内存优化

Java堆的唯一目的就是创建实例对象,几乎所有的对象都在堆上分配内存,如果堆空间分配内存出现问题可见是非常严重的。当Java 堆内存出现问题时,我们应该怎么去优化呢?在学习堆内存优化之前,我们要先了解一下有关堆内存优化的参数。堆在实现时,既可以实现成固定大小的,也可以是可扩展的,当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。     在这里通过程序测试一下:public c

点滴记录 1595

Unity Addressable资源缓存路径自定义指南:告别C盘爆满烦恼

本文详细介绍了如何自定义Unity Addressable系统的资源缓存路径,解决其默认存储在C盘导致的磁盘空间不足问题。通过配置CacheInitializationSettings并编写编辑器脚本,开发者可以将缓存迁移至项目目录,实现资源的集中管理,提升团队协作效率与开发环境一致性。

pytorch8learner的博客 474

ScanNet数据集下载全攻略:从申请到解析的保姆级教程(含常见问题解决)

本文提供了ScanNet数据集从申请授权到下载、解析的完整实战指南。针对这个大规模室内RGB-D数据集,详细介绍了官方申请流程、优化下载策略、数据验证方法,并重点解决了深度图解析等常见问题,帮助三维视觉研究者高效获取和使用这一宝贵资源。

5f4d3s2a1q的博客 617

选择您的收藏库

这真的是您应该烦恼的吗? java.util.ArrayList和java.util.HashMap从根本上有问题吗? 对于大多数源代码,答案是–不; 这些实现完全可以。 但是,一如既往,细节决定成败。 并存在情况下,当是内置到功能设置集合API不够充分,或者您找到标准的集合设置成开销太高了您的喜好。 在过去的几年中,我们不断地发现了同样的问题。 并且认为分享经验会很好–希望它可以...

最佳 Java 编程 129

鸿宇多用户商城user.php RCE漏洞复现

鸿宇多用户商城 user.php 存在任意命令执行漏洞,攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。

0xSec 1621

Java堆外内存的使用

最近经常有人问我在Java中使用堆外(off heap)内存的好处与用途何在。我想其他面临几样选择的人应该也会对这个答案感兴趣吧。 堆外内存其实并无特别之处。线程栈,应用程序代码,NIO缓存用的都是堆外内存。事实上在C或者C++中,你只能使用未托管内存,因为它们默认是没有托管堆(managed heap)的。在Java中使用托管内存或者“堆”内存是这门语言的一个特性。注意:Java并非唯一这

来啊 快活啊 7863

不加行也能填满:用 ABAP BDC 驯服 Table Control 滚动录制缺陷,批量维护供应商银行账户

摘要 本文探讨了在SAP ECC/S4HANA系统中处理供应商主数据时,Table Control控件带来的批量导入挑战。文章指出,银行账户维护界面中Table Control的滚动动作难以被录制工具捕捉,导致批量导入数据时仅能填充前5行。解决方案是通过BDC_OKCODE显式触发翻页(如=P+),并配合行号拼接(如(01)~(05))将数据写入不可见行。文中提供了完整的ABAP程序示例,展示了如何读取外部文件、动态生成BDCDATA、处理表格翻页逻辑,最终通过CALL TRANSACTION执行XK01事

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 270

SolidWorks2020详细步骤安装教程

1、在安装软件前请断开网络连接,需要安装.NETFramework3.5和4.0,最后还要确保把之前安装的旧版本完全卸载,以管理员身份运行SolidWorks_Flexnet_Server\server_remove.bat,然后等到服务“SolidWorksFlexnet服务器”将被删除。12、先不要运行软件,找到_SolidSQUAD_文件夹,将文件夹“ProgramFiles\SOLIDWORKSCorp”中的所有破解文件复制替到“ProgramFiles\SOLIDWORKSCorp”目录下;

qq_53545309的博客 1万+

java 堆外内存是什么意思_Java堆外内存之二:堆外内存使用总结

目录:有时候对内存进行大对象的读写,会引起JVM长时间的停顿,有时候则是希望最大程度地提高JVM的效率,我们需要自己来管理内存(看起来很像是Java像C++祖宗的妥协吧)。据我所知,很多缓存框架都会使用它,比如我以前使用过的EhCache(给它包装了个酷一点的名字,叫BigMemory),以及现在项目中的Memcached等。使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,...

weixin_29847829的博客 498

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

JVM——堆外内存详解

从这里看原文: JVM——堆外内存详解 内存是好东西,我们常听堆内存,很多人却不知道还有一个堆外内存。 那这两个都是个啥玩意呢?且让本帅博主今天给你好好说道说道。 一、堆内内存 那什么东西是堆内存呢?我们来看看官方的说法。 “Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。” 也就是说,平常我们老遇见的那位,JVM启动时分配的,就叫作堆内存(即堆内内存)。 对象的堆内存由称为垃圾回收器的自动内存管理系统回收。 此外,

积累与备忘 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

java中使用堆外内存,关于内存回收需要注意的事和没有解决的遗留问题(等大神解答)

JVM可以使用的内存分外2种:堆内存和堆外内存,堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,代码中能直接操作本地内存的方式有2种:使用未公开的Unsafe和NIO包下ByteBuffer。C语言的内存分配和释放函数malloc/free,必须要一一对应,否则就会出现内存泄露或者是野指针的非法访问。java中我们需要手动释放获取的堆外内存吗

aty 1万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

java 堆外内存_Java堆外内存之二:堆外内存使用总结

目录:有时候对内存进行大对象的读写,会引起JVM长时间的停顿,有时候则是希望最大程度地提高JVM的效率,我们需要自己来管理内存(看起来很像是Java像C++祖宗的妥协吧)。据我所知,很多缓存框架都会使用它,比如我以前使用过的EhCache(给它包装了个酷一点的名字,叫BigMemory),以及现在项目中的Memcached等。使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,...

weixin_39703773的博客 337

一文搞懂堆外内存(模拟内存泄漏)

平时编程时,在Java中创建对象,实际上是在堆上划分了一块区域,这个区域叫堆内内存。使用这-Xms -Xmx来指定新生代和老年代空间大小的初始值和最大值,这初始值和最大值也被称为 Java堆的大小,即堆内内存大小。这个堆内内存完全受 JVM管理,JVM有垃圾回收机制,所以我们一般不必关系对象的内存如何回收。剖开JVM内存模型,来看下其堆划分:由图可知Java8使用元空间替代永久代且元空间放在堆外内存上,这是为啥?类的元数据信息常用到,在GC时回收效率偏低。类的元数据信息。

jcc4261的博客 766

堆外内存的介绍及释放

热爱美好的事物,是一种追求 介绍 ____堆外内存意味着把内存对象分配在 Java 虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机), 作用:能缩短垃圾回收时间 ​ 适合生命期中等或较长的对象 特点: 对于大内存有良好的伸缩性,可以自行扩展 对垃圾回收停顿的改善可以明显感觉到,不影响用户线程 在进程间可以共享,减少虚拟机间的复制 如果使用的多,那么你可能会考虑硬盘的速度会有影响 堆外内存的回收 堆外内存的分配很简单,比如如下 ByteBuffer buffer = ByteBuffer

洛雪 1907

Java中的堆外内存具体是怎么实现的

当没有任何引用指向堆外内存时,GC会清理与堆外内存相关联的Cleaner对象,进而释放内存。使用ByteBuffer.allocateDirect()方法,Java的ByteBuffer类提供了allocateDirect()方法,用于在堆外内存中分配内存。由于堆外内存直接操作系统内存,因此它可以避免Java堆内存的限制,并且可以提高内存分配和访问的性能。在使用完堆外内存后,可以通过调用ByteBuffer的clear()或compact()方法来重置缓冲区,但这并不会释放内存。

怀揣梦想,一颗执着于技术的心从未磨灭,内心住着一颗顽强的小强时刻提醒自己层层突破自我,同时也成就他人 591

Java堆外内存之突破JVM枷锁

对于有Java开发经验的朋友都知道,Java中不需要手动的申请和释放内存,JVM会自动进行垃圾回收;而使用的内存是由JVM控制的。 那么,什么时机会进行垃圾回收,如何避免过度频繁的垃圾回收?如果JVM给的内存不够用,怎么办? 此时,堆外内存登场!利用堆外内存,不仅可以随意操控内存,还能提高网络交互的速度。 背景1:JVM内存的分配   对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下:   新生代:一般来说新创建的对象都分配在这里。   年老代:经过几次垃圾回收,新生代的对象.

Java_may的博客 158

java allocatememory_Java堆外内存之四:直接使用Unsafe类操作堆外内存

在nio以前,是没有光明正大的做法的,有一个work around的办法是直接访问Unsafe类。如果你使用Eclipse,默认是不允许访问sun.misc下面的类的,你需要稍微修改一下,给Type Access Rules里面添加一条所有类都可以访问的规则:在使用Unsafe类的时候:Unsafe f = Unsafe.getUnsafe();发现还是被拒绝了,抛出异常:java.lang.Se...

weixin_42316933的博客 1711

java visualvm远程监控_如何监控和诊断堆外内存使用

如何监控和诊断堆外内存使用可以使用综合性的图形化工具,如 JConsole、VisualVM ,这些工具比较直观,直接连接到 Java 进程,图形化界面。可以使用命令工具进行查询,如 jstat 和jmap 工具,查看堆、方法区等使用数据。使用 jmap 提供的命令, 生产 Heap Dump 文件,然后利用 Jhat 和 Eclipse MAT 进行分析。GC 日志输出,也能包含很多有用的信息。...

weixin_39796533的博客 812

jvm 堆外内存_如何监控和诊断堆外内存使用

如何监控和诊断堆外内存使用可以使用综合性的图形化工具,如 JConsole、VisualVM ,这些工具比较直观,直接连接到 Java 进程,图形化界面。可以使用命令工具进行查询,如 jstat 和jmap 工具,查看堆、方法区等使用数据。使用 jmap 提供的命令, 生产 Heap Dump 文件,然后利用 Jhat 和 Eclipse MAT 进行分析。GC 日志输出,也能包含很多有...

weixin_39592315的博客 875

使用堆外内存

使用堆外内存 有时候对内存进行大对象的读写,会引起JVM长时间的停顿,有时候则是希望最大程度地提高JVM的效率,我们需要自己来管理内存(看起来很像是Java像C++祖宗的妥协吧)。据我所知,很多缓存框架都会使用它,比如我以前使用过的EhCache(给它包装了个酷一点的名字,叫BigMemory),以及现在项目中的Memcached。在nio以前,是没有光明正大的做法的,有一个wo

lantian0802的专栏 1259

Java堆外内存之二:堆外内存使用总结

目录: 《堆外内存操作类ByteBuffer》 《DirectBuffer》 《Unsafe(java可直接操作内存(),挂起与恢复,CAS操作)》     有时候对内存进行大对象的读写,会引起JVM长时间的停顿,有时候则是希望最大程度地提高JVM的效率,我们需要自己来管理内存(看起来很像是Java像C++祖宗的妥协吧)。据我所知,很多缓存框架都会使用它,比如我以前使用过的EhCache...

weixin_33889245的博客 348

什么是堆内内存和堆外内存?

虽然第3种情况的ObjectInHeap存在内存泄露,但是这个类的设计是合理的,它很好的封装了直接内存,这个类的调用者感受不到直接内存的存在。这是因为ObjectInHeap对象是在堆内存中分配的,当该对象被垃圾回收的时候,并不会释放堆外内存,因为使用Unsafe获取的堆外内存,必须由程序显示的释放,JVM不会帮助我们做这件事情。java中我们需要手动释放获取的堆外内存吗?也即是说,使用ByteBuffer不用担心堆外内存的释放问题,除非堆内存中的 ByteBuffer对象由于错误编码而出现内存泄露。

Dc253061007的博客 263

netty堆外内存的使用

一、java的堆外内存 堆外内存的限额默认与堆内内存(由-XMX 设定)相同,可用 -XX:MaxDirectMemorySize 重新设定 1、优缺点 优点: (1)可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间; (2)理论上能减少GC暂停时间; (3)可以在进程间(系统调用,aio)共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现; (4)它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据 (5)堆外内存能减少IO时的内存复制,不需要堆内存Bu

tianyaleixiaowu的专栏 2228
上一篇: Linux的swappiness的配置
下一篇: pgAdmin在打开查询构造工具(Query Builder)时死掉的解决办法
fancyerII
博客等级 码龄23年 48粉丝 164原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值