Java堆外内存管理

时间:2023-01-09 09:38:29

Java堆外内存管理

 

1、JVM可以使用的内存分外2种:堆内存和堆外内存

堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。

使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,代码中能直接操作本地内存的方式有2种:使用未公开的Unsafe和NIO包下ByteBuffer。

使用ByteBuffer分配本地内存则非常简单,直接ByteBuffer.allocateDirect(10 * 1024 * 1024)即可。

C语言的内存分配和释放函数malloc/free,必须要一一对应,否则就会出现内存泄露或者是野指针的非法访问。java中我们需要手动释放获取的堆外内存吗?

我们一起来看看NIO中提供的ByteBuffer

Java堆外内存管理

我们将最大堆外内存设置成40M,运行这段代码会发现:程序可以一直运行下去,不会报OutOfMemoryError。如果使用了-verbose:gc -XX:+PrintGCDetails,会发现程序频繁的进行垃圾回收活动。那么DirectByteBuffer究竟是如何释放堆外内存的?

我们修改下JVM的启动参数,重新运行之前的代码:

Java堆外内存管理

与之前的JVM启动参数相比,增加了-XX:+DisableExplicitGC,这个参数作用是禁止代码中显示调用GC。代码如何显示调用GC呢,通过System.gc()函数调用。如果加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果,相当于是没有这行代码一样。

Java堆外内存管理

显然堆内存(包括新生代和老年代)内存很充足,但是堆外内存溢出了。也就是说NIO直接内存的回收,需要依赖于System.gc()。如果我们的应用中使用了java nio中的direct memory,那么使用-XX:+DisableExplicitGC一定要小心,存在潜在的内存泄露风险

我们知道java代码无法强制JVM何时进行垃圾回收,也就是说垃圾回收这个动作的触发,完全由JVM自己控制,它会挑选合适的时机回收堆内存中的无用java对象。代码中显示调用System.gc(),只是建议JVM进行垃圾回收,但是到底会不会执行垃圾回收是不确定的,可能会进行垃圾回收,也可能不会。什么时候才是合适的时机呢?一般来说是,系统比较空闲的时候(比如JVM中活动的线程很少的时候),还有就是内存不足,不得不进行垃圾回收。我们例子中的根本矛盾在于:堆内存由JVM自己管理,堆外内存必须要由我们自己释放;堆内存的消耗速度远远小于堆外内存的消耗,但要命的是必须先释放堆内存中的对象,才能释放堆外内存,但是我们又不能强制JVM释放堆内存。

2、Direct Memory的回收机制:

Direct Memory是受GC控制的,例如ByteBuffer bb = ByteBuffer.allocateDirect(1024),这段代码的执行会在堆外占用1k的内存,Java堆内只会占用一个对象的指针引用的大小,堆外的这1k的空间只有当bb对象被回收时,才会被回收,这里会发现一个明显的不对称现象,就是堆外可能占用了很多,而堆内没占用多少,导致还没触发GC,那就很容易出现Direct Memory造成物理内存耗光。

Direct ByteBuffer分配出去的内存其实也是由GC负责回收的,而不像Unsafe是完全自行管理的,Hotspot在GC时会扫描Direct ByteBuffer对象是否有引用,如没有则同时也会回收其占用的堆外内存。

使用堆外内存与对象池都能减少GC的暂停时间,这是它们唯一的共同点。生命周期短的可变对象,创建开销大,或者生命周期虽长但存在冗余的可变对象都比较适合使用对象池。生命周期适中,或者复杂的对象则比较适合由GC来进行处理。然而,中长生命周期的可变对象就比较棘手了,堆外内存则正是它们的菜。

3、堆外内存的好处是:

(1)可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间;

(2)理论上能减少GC暂停时间;

(3)可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现;

(4)它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据

站在系统设计的角度来看,使用堆外内存可以为你的设计提供更多可能。最重要的提升并不在于性能,而是决定性的。

 

Java堆外内存管理的更多相关文章

  1. cassandra 堆外内存管理

    为什么需要堆外内存呢 单有一些大内存对象的时候,JVM进行垃圾回收时需要收集所有的这些对象的内存也.增加了GC压力.因此需要使用堆外内存. java 分配堆外内存 org.apache.cassand ...

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

    目录: <堆外内存操作类ByteBuffer> <DirectBuffer> <Unsafe(java可直接操作内存(),挂起与恢复,CAS操作)> 有时候对内存进 ...

  3. google-perftools 分析JAVA 堆外内存

    google-perftools 分析JAVA 堆外内存 分类: j2se2011-08-25 21:48 3358人阅读 评论(4) 收藏 举报 javahbasehtml工具os 原文转自:htt ...

  4. 实战经验 &vert; Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

  5. 超干货!Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

  6. Java堆外内存之五:堆外内存管理类ByteBuffer

    本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...

  7. Java堆外内存之四:直接使用Unsafe类操作堆外内存

    在nio以前,是没有光明正大的做法的,有一个work around的办法是直接访问Unsafe类.如果你使用Eclipse,默认是不允许访问sun.misc下面的类的,你需要稍微修改一下,给Type ...

  8. Java堆外内存之三:堆外内存回收方法

    一.JVM内存的分配及垃圾回收 对于JVM的内存规则,应该是老生常谈的东西了,这里我就简单的说下: 新生代:一般来说新创建的对象都分配在这里. 年老代:经过几次垃圾回收,新生代的对象就会放在年老代里面 ...

  9. Java堆外内存之六:堆外内存溢出问题排查

    一.堆外内存组成 通常JVM的参数我们会配置 -Xms 堆初始内存 -Xmx 堆最大内存 -XX:+UseG1GC/CMS 垃圾回收器 -XX:+DisableExplicitGC 禁止显示GC -X ...

随机推荐

  1. Spring MVC &commat;RequestMapping Annotation Example with Controller&comma; Methods&comma; Headers&comma; Params&comma; &commat;RequestParam&comma; &commat;PathVariable--转载

    原文地址: @RequestMapping is one of the most widely used Spring MVC annotation.org.springframework.web.b ...

  2. C&num;&lowbar;LINQ(LINQ to Entities)

    LINQ to Entities 是 LINQ 中最吸引人的部分.它让你可以使用标准的 C# 对象与数据库的结构和数据打交道.使用 LINQ to Entities 时,LINQ 查询在后台转换为 S ...

  3. Express框架学习总结

    最近学了Express框架,在学习的过程中,参考了一些资料,感觉Express框架比原生Node.js好用多了.下面我将我学习总结的内容如下: Express中文网     http://www.ex ...

  4. centos下Elasticsearch数据迁移与备份

    ########### ### 共享创建es官方网站就一句话 ########   1.下载 文件共享 .. rpm -i http://mirror.symnds.com/distributions ...

  5. Spring MVC 和Struts2对比

    Spring MVC和Struts2的区别: 1. 机制:spring mvc的入口是servlet,而struts2是filter,这样就导致了二者的机制不同. ​2. 性能:spring会稍微比s ...

  6. 05&lowbar;Elasticsearch 单模式下API的增删改查操作

    05_Elasticsearch 单模式下API的增删改查操作 安装marvel 插件: zjtest7-redis:/usr/local/elasticsearch-2.3.4# bin/plugi ...

  7. iOS安全攻防(二十三):Objective-C代码混淆

    iOS安全攻防(二十三):Objective-C代码混淆 class-dump能够非常方便的导出程序头文件,不仅让攻击者了解了程序结构方便逆向,还让着急赶进度时写出的欠完好的程序给同行留下笑柄. 所以 ...

  8. Esxi主机虚拟机迁移注意事项

    1. Esxi主机上的虚拟机迁移只能是低----->高,或版本一样的才能进行迁移 [如Esxi5.1---->Esxi5.5]ok, 而Esxi5.5----->Esxi5.1 no ...

  9. POJ-2926-Requirements&amp&semi;&amp&semi;Educational Codeforces Round 56G&period; Multidimensional Queries 【哈夫曼距离】

    POJ2926 先学会这个哈夫曼距离的处理才能做 cf 的G #include <iostream> #include <stdio.h> #include <algor ...

  10. 通过命令修改mysql的提示符

    在cmd窗口操作mysql数据库的时候,前面的提示符永远都是mysql>,这个提示符可以通过命令修改. 在登录mysql时修改: mysql -uroot -p --prompt 提示符 登录后 ...