怎么拍出jvm使用的堆外jvm 大内存使用情况

&&&&JVM可以使用的内存分外2种:堆内存和堆外内存.
&&&&堆内存完全由JVM负责分配和释放,如果程序没有缺陷代码导致内存泄露,那么就不会遇到java.lang.OutOfMemoryError这个错误。
&&&&使用堆外内存,就是为了能直接分配和释放内存,提高效率。JDK5.0之后,代码中能直接操作本地内存的方式有2种:使用未公开的Unsafe和NIO包下ByteBuffer。
&&&&关于Unsafe对象的简介和获取方式,可以参考:http://blog.csdn.net/aitangyong/article/details/
&&&&使用ByteBuffer分配本地内存则非常简单,直接ByteBuffer.allocateDirect(10 * 1024 * 1024)即可。
&&&&C语言的内存分配和释放函数malloc/free,必须要一一对应,否则就会出现内存泄露或者是野指针的非法访问。java中我们需要手动释放获取的堆外内存吗?
&&&&我们一起来看看NIO中提供的ByteBuffer
&&&&& 我们将最大堆外内存设置成40M,运行这段代码会发现:程序可以一直运行下去,不会报OutOfMemoryError。如果使用了-verbose:gc -XX:+PrintGCDetails,会发现程序频繁的进行垃圾回收活动。那么DirectByteBuffer究竟是如何释放堆外内存的?
&&& 我们修改下JVM的启动参数,重新运行之前的代码:
&&&&& 与之前的JVM启动参数相比,增加了-XX:+DisableExplicitGC,这个参数作用是禁止代码中显示调用GC。代码如何显示调用GC呢,通过System.gc()函数调用。如果加上了这个JVM启动参数,那么代码中调用System.gc()没有任何效果,相当于是没有这行代码一样。
&&&&& 显然堆内存(包括新生代和老年代)内存很充足,但是堆外内存溢出了。也就是说NIO直接内存的回收,需要依赖于System.gc()。如果我们的应用中使用了java nio中的direct memory,那么使用-XX:+DisableExplicitGC一定要小心,存在潜在的内存泄露风险。
&&&& 我们知道java代码无法强制JVM何时进行垃圾回收,也就是说垃圾回收这个动作的触发,完全由JVM自己控制,它会挑选合适的时机回收堆内存中的无用java对象。代码中显示调用System.gc(),只是建议JVM进行垃圾回收,但是到底会不会执行垃圾回收是不确定的,可能会进行垃圾回收,也可能不会。什么时候才是合适的时机呢?一般来说是,系统比较空闲的时候(比如JVM中活动的线程很少的时候),还有就是内存不足,不得不进行垃圾回收。我们例子中的根本矛盾在于:堆内存由JVM自己管理,堆外内存必须要由我们自己释放;堆内存的消耗速度远远小于堆外内存的消耗,但要命的是必须先释放堆内存中的对象,才能释放堆外内存,但是我们又不能强制JVM释放堆内存。
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来进行处理。然而,中长生命周期的可变对象就比较棘手了,堆外内存则正是它们的菜。
堆外内存的好处是:
(1)可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间;
(2)理论上能减少GC暂停时间;
(3)可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现;
(4)它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据
站在系统设计的角度来看,使用堆外内存可以为你的设计提供更多可能。最重要的提升并不在于性能,而是决定性的
堆外内存说明请参见:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
阅读(...) 评论()请教java堆外内存泄漏分析定位方法? - 讨论 - 高级语言虚拟机 - ITeye群组
&& 我有一个java应用, 堆最大设为1g, 当运行几天后就会发现java进程的内存消耗会达到7个多G,导致应用挂掉。请教各位高手java堆外内存泄漏分析定位方法。
堆外内存泄露,一般是系统中使用压缩和 NIO 导致。
具体原因可以用perftools看看。
你这个问题我好像也遇到过,貌似NIO分配的堆外内存不fullGC的话,收不回来,然后再JVM堆里面只是存一些堆外内存引用的指针很小,在JVM达到fullGC的标准之前,堆外内存已经分配的很恐怖了,我们系统是因为NIO的ByteBuffer分配了很多堆外内存没回收导致的。不过具体的原理我还没搞清楚,等着大大来解释下。
jvm是怎样管理堆外分配的内存呢? 求解惑啊?
看看R大关于这篇贴的回复& http://hllvm./group/topic/28866?page=2
“堆外”这个词太模糊了所以我不建议这样用。“堆”是什么?一般Java上下文里说的“堆外”有可能指“Java heap”外,也有可能指“GC heap”外。在更一般的上下文里可能会指“C heap”外,或者根本就不用“堆外”这种说法。JVM自己运行也要用一些空间;进程中其它的代码(非JVM的代码)也有可能申请、使用一些空间。JVM并没有控制到整个进程里所有的内存。所以“堆外”分配的内存是怎么管理的呢?有很大一部分“堆外”空间根本就不在JVM的管理下。这个问题本身出发点就有偏差。NIO direct memory是从C heap分配出来的,实际上JVM也不关心这些内存;这是库(class library)的部分关心的,而不是JVM关心的。
william_ai 写道堆外内存泄露,一般是系统中使用压缩和 NIO 导致。
具体原因可以用perftools看看。
请问perftools这个工具怎么用呢?
已经生产test_.heap文件,怎么统计结果呢?
执行bin/pprof --text $JAVA_HOME/bin/java test_.heap
会提示:
The first profile should be a remote form to use /pprof/symbol
Dumping heap profile to /home/user/perftools/test_.heap (Exiting)
怎么样才能产生类似这样的结果呢?
Total: 3263.2 MB&
& .4%& 96.4%&& .4% zcalloc&
&&& 83.8&& 2.6%& 99.0%&&&& 83.8&& 2.6% os::malloc&
&&& 30.0&& 0.9%& 99.9%&&&& 30.0&& 0.9% init&
&&&& 2.2&& 0.1%& 99.9%&&&&& 2.2&& 0.1% ObjectSynchronizer::omAlloc&
&&&& 1.0&& 0.0% 100.0%&& .4% Java_java_util_zip_Deflater_init&
&&&& 0.6&& 0.0% 100.0%&&&&& 0.7&& 0.0% readCEN&如何查看jvm堆外内存使用情况? - 知乎13被浏览1131分享邀请回答5添加评论分享收藏感谢收起java.lang.OutOfMemoryError: Direct buffer memory浣跨敤鍫嗗?鍐呭瓨[杞琞 - 浜虹О楗煎摜 - ITeye鍗氬?
鍗氬?鍒嗙被锛

我要回帖

更多关于 jvm 大内存使用情况 的文章

 

随机推荐