一、堆外内存组成

通常JVM的参数我们会配置

-Xms 堆初始内存
-Xmx 堆最大内存
-XX:+UseG1GC/CMS 垃圾回收器
-XX:+DisableExplicitGC 禁止显示GC
-XX:MaxDirectMemorySize 设置最大堆外内存,默认是-xmx-survivor,也就是基本上和-xmx大小相等
-Xss:每个线程的堆栈大小,默认1M
-Xmn: 年轻代大小(eden区+2 survivor)
-XX:newRatio: 4 年轻代与老年代1:4
-XX:survivorRatio: 8Eden区与survivor大小比值

java整个进程占用的内存:
- 堆内存
- metaspace(堆内) JDK8使用metaspace来替代了permsize:永久代大小
- 堆外内存使用
- 线程栈空间

堆外内存回收: 堆外内存的回收是通过system.gc()来的,依赖于目前的gc机制。
通常是通过DirectByteBuffer对象来分配堆外内存,gc的时候就是判断这个对象是否被引用,来决定是否回收。

二、堆外内存参数配置

-XX:InitialCodeCacheSize=64M \
-XX:CodeCacheExpansionSize=1M \
-XX:CodeCacheMinimumFreeSpace=1M \
-XX:ReservedCodeCacheSize=200M \
-XX:MinMetaspaceExpansion=1M \
-XX:MaxMetaspaceExpansion=8M \
-XX:MaxDirectMemorySize=96M \
-XX:CompressedClassSpaceSize=256M \

三、问题排查

3.1、首先确认堆占用

1、用jmap,jmap 查看heap内存使用情况

jmap -heap pid

可以查看到MetaspaceSize,CompressedClassSpaceSize,MaxMetaSize
jmap和jdk版本有关系,有些jdk版本会查看不到内存信息,可以使用jstat来查看统计信息

2、jstat 收集统计信息

jstat -gc pid 1000
S0C/S0U S1C/S1U EC/EU CCSC/CCSU YGC/YGCT FGC/FCGT GCT
survivor0容量和使用 survivor1容量和使用 Eden jdk8是meta,以前应该是PC,PC young gc次数和耗时 full gc次数和耗时 total gc时间

如果能排除掉heap的问题,就要分析堆外内存情况了。

3.2、分析堆外情况

NMT(native memory tracking)
使用
在JVM参数中添加 -XX:NativeMemoryTracking=[off | summary | detail]

-XX:NativeMemoryTracking=detail

在JVM运行过程中,使用jcmd获取相关信息
jcmd pid VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

jcmd pid VM.native_memory detail

baseline个基准,之后会输出diff参数,来和这个基线版本进行比较,可以两次的内存差

NMT报告会显示内存使用情况

类别                  含义
Java Heap        堆大小
Thread              线程
Thread Stack    线程栈

NMT可以得到线程栈大小,排除栈空间影响。

pmap 查看进程内存地址空间

pmap -x pid | sort xx

可以结合pmap,和nmt得到内存地址空间。和堆外占用情况了。

接下来需要做的就是分析堆外内存的内容了。

gdb dump查看内存空间内容

gdb dump查看内存空间内容

(gdb) dump binary memory ./file BEGIN_ADDRESS END_ADDRESS

将内存内容dump到文件中,就可以查看到文件中的内容了。
但是这种方式不直观,所以可以使用其他工具

gperf
google的,使用gperf2.5即可,网上很多安装都说一定要安装libunwind,其实都是瞎抄抄,老版本确实需要,2.5的版本不需要了。

https://blog.csdn.net/unix21/article/details/79161250
另外一个注意点就是虽然heap文件只有1M,但是可以分析出堆外内存的大小。
不过我在实际使用过程中,gperf并没有分析出实际的堆外内存情况,通过pmap可以看出堆外内存占用有几个G,但是gperf始终只有200M

Jemalloc
https://github.com/jemalloc/jemalloc/releases
安装

./configurate –enable-prof
make
sudo make install
配置

export LD_PRELOAD=/usr/local/lib/libjemalloc.so
export MALLOC_CONF=prof:true,lg_prof_interval:31,lg_prof_sample:17,prof_prefix:/output/jeprof
https://github.com/jemalloc/jemalloc/wiki/Getting-Started

环境:基于B\S的点子考试系统,为了发现客户端能实时地从服务端接收考试数据,系统使用了逆向AJAX技术(也称Comet或Server Side Push),选用CometD1.1.1作为服务端推送框架,服务器是Jetty7.1.4,硬件为一台普通PC机,Core i5 CPU,

4G内存,运行32位Windows操作系统。

说明:测试期间发现服务端不定时抛出内存溢出异常,服务器不一定每次都会出现异常,但是假如正式考试时奔溃一次,那估计整场考试都会全乱套,网站管理员尝试过把堆开到最大,32位系统最多到1.6GB基本无法再加大了,而且开大量也基本没效果,抛出

内存溢出异常好像更加繁琐了。加入-XX:+HeapDumpOnOutOfMemoryError,居然也没有任何反应,抛出内存溢出异常时什么文件都没产生。无奈之下只好挂着jstat使劲盯屏幕,发现GC并不频繁,Eden区,Survivor区,老年代及拥挤代内存全部

表示"情绪稳定,压力不大",但是照样不停的抛出内存溢出异常,管理员鸭梨很大。最后,在内存溢出后从系统日志中找到异常堆栈。

分析:大家都知道操作系统对每个进程能管理的内存是有限的,这台服务器使用的32位Windows平台的限制是2GB,其中给了Java堆1.6GB,而Direct Memory 并不算在1.6GB的堆之内,因此它只能在剩余的0.4GB空间分出一部分。在此应用中导致内

存溢出的关键是:垃圾收集进行时,虚拟机虽然会对Direct Memory进行回收,但是Direct Memory 却不能像新生代和老年代那样,发现空间不足了就通知收集器进行垃圾回收,他只能等到抛出内存溢出异常时,先catch掉,再在catch块里面“大喊”

“System.gc”.要是虚拟机还是不听(如:打开了-XX:+DisableExplicitGC开关),那就只能眼睁睁地看着堆中还有许多空闲内存,自己却不得不抛出内存异常了。而本案例中使用的Comet1.1.1框架,正好有大量的NIO操作需要用到Direct Memory。

总结:从实践经验来看,除了java堆和永久代之外,我们注意到下面这些区域也会占用较多的内存,这里所有的内存总和会受到操作系统进程最大内存的限制:

1.Direct Memory:可以通过-XX:MaxDirectMemorySize调整大小,内存不足时抛出OutOfMemoryError或OutOfMemoryError:Direct buffer memory。

2.线程堆栈:可通过-Xss调整大小内存不足时抛出StackoverflowErroe(纵向无法分配,即无法分配新的栈帧)或OutOfMemoryError:unable to create new native thread(横向无法分配,即无法建立新的线程)。

3.Socket缓存区:每个Socket连接都Receive和Send两个缓存区,分别占大约37KB和25KB的内存,连接多的话这块内存占用也比较可观。如果无法分配,则可能会抛出IOException:Too many open files异常。

4.JNI代码:如果代码中使用JNI调用本地库,那么本地库使用内存也不在堆中

5.虚拟机和GC:虚拟机和GC的代码执行也要消耗一定的内存。

Java堆外内存之六:堆外内存溢出问题排查的更多相关文章

  1. 深入了解java虚拟机(JVM) 第三章 内存区域----堆空间

    一.堆的含义 jvm堆的区域主要是用来存放对象的实例,它的空间大小是JVM内存区域中占比重最大的,也是jvm最大的内存管理模块,最重要的是,这个区域是垃圾收集器主要管理的区域,这意味着我们在考虑垃圾回 ...

  2. java中栈内存与堆内存(JVM内存模型)

    java中栈内存与堆内存(JVM内存模型) Java中堆内存和栈内存详解1 和 Java中堆内存和栈内存详解2 都粗略讲解了栈内存和堆内存的区别,以及代码中哪些变量存储在堆中.哪些存储在栈中.内存中的 ...

  3. 求你了,别再说Java对象都是在堆内存上分配空间的了!

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解.可以说,关于JVM的相关知识,基本是每个Java开发者 ...

  4. 别再说Java对象都是在堆内存上分配空间的了!

    Java作为一种面向对象的,跨平台语言,其对象.内存等一直是比较难的知识点,所以,即使是一个Java的初学者,也一定或多或少的对JVM有一些了解.可以说,关于JVM的相关知识,基本是每个Java开发者 ...

  5. JVM知识(一) 求你了,别再说Java对象都是在堆内存上分配空间的了!

    求你了,别再说Java对象都是在堆内存上分配空间的了! https://baijiahao.baidu.com/s?id=1661296872935371634&wfr=spider& ...

  6. Java直接内存与堆内存

    NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer. DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通 ...

  7. 【转载】java项目中经常碰到的内存溢出问题: java.lang.OutOfMemoryError: PermGen space, 堆内存和非堆内存,写的很好,理解很方便

    Tomcat Xms Xmx PermSize MaxPermSize 区别 及 java.lang.OutOfMemoryError: PermGen space 解决 解决方案 在 catalin ...

  8. JAVA面试题:String 堆内存和栈内存

    java把内存划分为两种:一种是栈(stack)内存,一种是堆(heap)内存 在函数中定义的一些基本类型的变量和对象的引用变量都在栈内存中分配,当在一段代码块定义一个变量时,java就在栈中为这个变 ...

  9. Java虚拟机内存区域堆(heap)的管理

    在上一节中Java 出现内存溢出的定位以及解决方案 中对于Java虚拟机栈以及方法区的内存出现的异常以及处理方式进行了解析,由于Java虚拟机对于堆的管理十分复杂,并且Java虚拟机中最基本的内存区域 ...

随机推荐

  1. sring 监听器

    参考链接:http://blog.csdn.net/ysughw/article/details/8992322 sring容器在web程序中获取的方式:http://blog.csdn.net/aq ...

  2. Struts2的手工自定义验证--完整实例代码

    ActionSupport类实现了Validateable.ValidationAware接口, 其中Validateable接口就是验证器接口,该接口有一个validate()方法, validat ...

  3. Apache自带性能测试工具ab的使用

    Apache服务器套件自带ab,只要安装Apache即可,无需另行安装ab.ab位于%ApacheHome%/bin目录下(“%ApacheHome%”为Aapche安装路径),你也可以把ab.exe ...

  4. DevExpress v17.2新版亮点—DevExtreme篇(二)

    用户界面套包DevExpress DevExtreme v17.2终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExtreme v17.2 的New Color Sche ...

  5. 移动端 解决自适应 和 多种dpr (device pixel ratio) 的 [淘宝] 解决方案 lib-flexible

    其实H5适配的方案有很多种,网上有关于这方面的教程也非常的多. 不管哪种方法,都有其自己的优势和劣势. 为什么推荐使用Flexible库来做H5页面的终端设备适配呢?   原理  简单易懂  源码疑问 ...

  6. Ubuntu:搜狗输入法不能输入中文

    搜狗输入法不能输入中文 问题描述 可以打开搜狗输入法,可以打英文,但是不能切换成中文. 其他输入法正常使用(这个可以判断是不是fcitx是不是出现错误). 有一个关于sogou的内部错误提示 解决方法 ...

  7. .Net Entity Framework Core 用 HasColumnType 配置浮点数精度

    一.前言 前段时间用.Net Entity Framework core搭建框架,需要配置浮点数的精度,发现.Net Entity Framework core 并没有HasPrecision方法.在 ...

  8. SWIFT中函数返回值为Tuple

    在playgroundm内键入以下代码,求一个成绩数组内最大分值和最小分值 func maxminScore(scores:Array<Int>) -> (maxScore:Int, ...

  9. QAV250四轴穿越机安装全程详解(多图)

    QAV250四轴穿越机安装全程详解 最近团队准备使用轻型穿越机QAV250做实验,本文记录了QAV250的安装过程,整理了开箱后较合理的安装顺序,以及各个步骤的注意事项,希望对有需要的朋友有所帮助.主 ...

  10. sql,去重

    distinct SELECT distinct nf FROM BSHGJJK.T_JJ_NY_QSNCJBQK order by nf desc 来自为知笔记(Wiz)