非原创,来自于同事的邮件分享。
前段时间在测试过程中发现了mina
框架的问题:当mina
一次传输的文件超过一定值(如55m
)或者连续传输文件的次数过于频繁,就会内存溢出:
org.apache.mina.filter.codec.ProtocolEncoderException:
java.lang.OutOfMemoryError: Java heap space
at
org.apache.mina.filter.codec.ProtocolCodecFilter.filterWrite(ProtocolCodecFilter.java:217)
at
org.apache.mina.common.support.AbstractIoFilterChain.callPreviousFilterWrite(AbstractIoFilterChain.java:361)
at
org.apache.mina.common.support.AbstractIoFilterChain.access$1300(AbstractIoFilterChain.java:53)
at
org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.filterWrite(AbstractIoFilterChain.java:659)
at
org.apache.mina.common.support.AbstractIoFilterChain$TailFilter.filterWrite(AbstractIoFilterChain.java:587)
at
org.apache.mina.common.support.AbstractIoFilterChain.callPreviousFilterWrite(AbstractIoFilterChain.java:361)
at
org.apache.mina.common.support.AbstractIoFilterChain.fireFilterWrite(AbstractIoFilterChain.java:355)
at
org.apache.mina.transport.socket.nio.SocketSessionImpl.write0(SocketSessionImpl.java:166)
at
org.apache.mina.common.support.BaseIoSession.write(BaseIoSession.java:177)
at
org.apache.mina.common.support.BaseIoSession.write(BaseIoSession.java:168)
at
com.taobao.forest.server.DefaultPushTimeTask.pushcachetothesession(DefaultPushTimeTask.java:441)
1
)
开始是尝试用常规方法试图分析mina
在内存溢出时什么东东占了那么多内存还无法释放,于是在jboss
启动参数那加了两个参数-XX:HeapDumpPath=\tmp
-XX:+HeapDumpOnOutOfMemoryError
,
作用是在发生OutOfMemoryError
时将当时的内存映像dump
到/tmp
下,然后将dump
出来的内存映像文件下到本地用mat
分析,不过分析结果未发现有内存溢出问题,甚是奇怪。
2
)之后,又上网查了些资料,才发现mina
不是用的堆内存(Heap
),而是使用的本机直接内存(Direct Memory
)
所谓本地直接内存
并不是虚拟机运行时数据区的一部分,它根本就是本机内存
而不是VM
直接管理的区域。
在JDK1.4
中新加入了NIO
类,引入一种基于渠道与缓冲区的I/O
方式,它可以通过本机Native
函数库直接分配本机内存
,然后通过一个存储在Java
堆里面的DirectByteBuffer
对象作为这块内存
的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java
对和本机堆中来回复制数据。显然本机直接内存
的分配不会受到Java
堆大小的限制,但是即然是内存
那肯定还是要受到本机物理内存
(包括SWAP
区或者Windows
虚拟内存
)的限制的,一般服务器管理员配置JVM
参数时,会根据实际内存
设置-Xmx
等参数信息,但经常忽略掉直接内存
,使得各个内存
区域总和大于物理内存
限制(包括物理的和操作系统级的限制),而导致动态扩展时出现OutOfMemoryError异常
。
此外,按照jvm
规范,本地直接内存的最大值按以下顺序设定:
(1
)通过-XX:MaxDirectMemorySize=<size>
指定值
(2
)若(1
)未满足,则就取maxMemory
,也就是通过-Xmx
设定的值;
(3
)若(1
)、(2
)都未满足,则取默认值:64M
;
根据以上知识,结合此次测试情况,问题基本水落石出:
在我们测试日常机中,系统启动的时候设定-Xmx 3072m
,没有通过-XX:MaxDirectMemorySize
设定本地直接内存最大值,因此本地直接内存最大值就是-Xmx
设定的值3072m
,整个系统的物理内存为4G
,除掉系统进程占用的内存,剩下的物理内存加上swap
空间也就接近3G
。设想JVM
的
heap size
占用了1.5G
,direct memory
使用了1.5G
,这时候程序申请一100M
的direct
内存,在这种情况下无论是JVM heap size
还是direct memory
不满足触发gc
的条件,于是jvm
向os
申请分配内存,但是OS
却无可分配的内存了,于是就会抛出OutOfMemoryError
错误。
因此,在使用NIO
框架时的时候一定要注意:
如果该NIO
框架使用的直存,需谨慎设定JVM
运行参数,最好用-XX:MaxDirectMemorySize
进行设定,否则你就得清楚你设定的-Xmx
不单单制定了heap size
的最大值,它同时也是direct memory
的最大值;
再大概补充一下NIO
和OOM
知识:
一、
首先对于可用内存这一概念的理解
在32
位机器上,CPU
可寻址的物理内存空间最大是4G
,超出4G
将不再可见。【此处忽略PAE
支持,如果进程中使用了AWE(windows)
或者mmap(linux)
一类的方案,这里暂时不管了】
这4G
的物理内存空间又分为用户空间和内核空间。默认情况下,windows
按照50:50
的比例划分,linux
默认下用户空间3G
,内核空间1G
。
所以一个进程可用的物理内存空间,在linux32
位机器下,就是3G
。而在64
位机器下,基本上可以认为是没有任何限制,原理很简单了。。。
不管是linux
还是windows
,可用内存空间由:物理内存+swap/
虚拟内存组成。Linux
上称作swap
【交换空间】,windows
上称作虚拟内存,本质上都是拿磁盘的一块地方当作物理内存使用。程序是不用关心使用的是物理内存,还是swap
;程序操作的是虚拟地址空间, OS
再将虚拟地址空间映射到物理内存、文件或者其他。不管是操作物理内存,还是swap
,对于程序来说完全是透明的。
Swap/
虚拟内存啥时候会使用,这个我也没完全搞清楚,不过有一点应该没错的,就是进程新申请的内存,不会在swap/
虚拟内存中分配,而是直接在物理内存中分配。当内存紧张时,OS
会将活动进程中占用的内存,从物理内存中交换出来,放到Swap/
虚拟内存上(有时甚至内存不紧张也会这么干)。当进程恢复活动时,OS
再将数据从swap/
虚拟内存空间中读出来放到物理内存中
所以当需要分析和计算进程需要占用的内存空间时,可以简单地忽略swap/
虚拟内存的概念
【这一点需要深入再论证一下!】
二、
JVM
对内存的管理
画一张图,很容易就可以理解了,下面这个圆表示jvm
进程所占用的所有的内存空间,分成三部分:
1.
堆空间
包括年轻化、年老代、持久域【以SUN HOTSPOT
虚拟机实现为例,其他虚拟机会有区别,比如IBM
的虚拟机,所谓的“
持久域”
不是在堆分配,而是在本地内存】
如果这个空间不够了,会抛出java.lang.OutOfMemoryError
2.
栈空间
每个线程都会有一个单独的stack
空间,JDK5.0
以前默认好象是256K
,JDK5.0
默认是1M
,很大的一个数值,可以通过-Xss
设置。如果这个空间不够了,会抛出java.lang.StackOverflowError
3.
本地内存
Jvm
进程可使用的内存,
除去堆、栈空间之后,剩下来的就是本地内存
以上三个空间加起来的内存,就是最终jvm
进程所使用的所有内存。如果是在32
位机器下,不能超过用户空间大小,即3G
;在64
位机器下,就要看物理内存的大小了
另再提醒一下大家,在发生了内存不足时,一味地增加-Xms
和-Xmx
,很有可能会适得其反,道理应该很明显了。需要看OOM
的类型,是堆不足,还是栈(StackOverFlow)
不足,还是本地内存不足native memory
。jvm
一般都会有足够的信息提示的。
三、
Nio
的direct memory allocate
我理解的,NIO
的直接内存分配【DMA
】,应该是从本地内存区域中分配内存。像前面讲的,如果不使用-XX:MaxDirectMemorySize
设置,那它就会使用-Xms
的设置,以日常测试环境为例, 这种情况下DMA
需要3G
,堆也需要3G,
很明显实际上这两个空间得到的内存都不可能这么大,所以要么是堆空间被挤压,拿不到3G
,要么是DMA
拿不到足够的空间
看jvm
抛出来的错误,应该是堆空间被挤压导致的。如果是本地内存不足,抛出的应该是OutOfMemoryError :Direct buffer
memory
,可以看一下java.nio.
DirectByteBuffer
这个类的源码,98
行
四、
NIO2.0
的改进
NIO
的DMA
,性能肯定比在堆中分配要好得多,因为是直接操作本地内存,避免了数据在JVM
Heap
和本地内存之间的拷贝操作,尤其是数据量较大时应该更加明显。
- 大小: 17.9 KB
分享到:
相关推荐
OOM 问题排查过程实战记录 一、OOM 问题排查过程概述 在 Java 应用程序中,OutOfMemoryError 是一种常见的异常,它可能是由于堆空间不足、永久代空间不足或是无法分配对象所引发的。在本文中,我们将通过一个实战...
本篇将通过一个简单的OOM例子来探讨这个问题的发生原因、如何复现以及如何进行问题排查。 一、OOM现象与原因 当Java应用出现OOM时,JVM会抛出`java.lang.OutOfMemoryError`异常。这通常由以下几种情况引起: 1. *...
OOM全称”Out Of Memory”,即内存溢出。 内存溢出已经是软件开发历史上存在了近40年的“老大难”问题。在操作系统上运行各种软件时,软件所需申请的内存远远超出了物理内存所承受的大小,就叫内存溢出。 内存溢出...
当程序出现性能问题或者"OutOfMemoryError"(OOM)时,理解堆内存的使用情况就显得尤为关键。"JVM堆内存分析工具"如HA(HeapAnalyzer)和MAT(Memory Analyzer Tool)就是专门为此设计的,它们能够帮助开发者深入...
当应用程序出现Out of Memory (OOM)错误时,通常意味着系统无法分配足够的内存来执行任务,这时就需要借助专业的分析工具来查找问题的根源。MemoryAnalyzer(MAT)是IBM开发的一款强大的JVM堆内存分析工具,它能够...
java jvm 中关于内存溢出分享,举例说明各种情况下可能会出现的oom事故
在Android开发中,由于内存管理机制的特性,开发者经常面临一个棘手的问题——Out Of Memory (OOM)。尤其是在处理图片时,如果不加以控制,大量图片的加载和显示可能导致应用程序崩溃。"Android相册图片解决OOM问题...
在Spark运行过程中,内存溢出(OOM)问题可能导致任务失败,影响整个应用程序的效率。本篇文章主要探讨Spark面对OOM问题的解决方法及优化策略。 首先,我们需要了解Spark的内存模型。Spark的Executor内存分为三个...
然而,在处理大量的帧动画时,可能会遇到内存溢出(Out Of Memory, OOM)的问题,这严重影响了用户体验,特别是在SurfaceView中加载动画时。本文将深入探讨如何解决帧动画引发的OOM问题,以及如何确保动画流畅运行。...
在Android开发中,"图片OOM"是一个常见的问题,全称为"Out Of Memory",即内存溢出异常。当应用程序在运行过程中,分配给它的内存不足以处理当前的操作时,就会发生这种异常。尤其在处理大量或者高分辨率的图片时,...
综上所述,解决GridView中的OOM问题主要依赖于有效的内存管理和图片加载策略。通过使用LruCache进行图片缓存,配合合适的图片尺寸调整,以及合理的多图下载策略,可以显著减少内存消耗,提高应用性能,从而避免出现...
线上问题排查是开发和运维工作中的一个重要组成部分,其目的是为了快速定位和解决问题,保证系统的稳定运行。在排查问题的过程中,使用合适的方法和工具至关重要,它们可以帮助我们更高效地进行问题分析和定位。下面...
基本上解决了OOM问题 如果 方便可以直接引用BitmapManager类到 项目中使用 解决blog 地址http://www.cnblogs.com/liongname/articles/2345087.html
在Android开发中,图片加载是常见的任务,但同时也是导致内存溢出(Out Of Memory, OOM)问题的主要原因之一。特别是当处理大量图片,如在ListView或RecyclerView中滚动时,如果没有正确的图片管理策略,图片加载...
如果在Keras内部多次使用同一个Model,例如在不同的数据集上训练同一个模型进而得到结果,会存在内存泄露的问题。在运行几次循环之后,就会报错OOM。 解决方法是在每个代码后面接clear_session()函数,显示的关闭TF...
本篇文章将深入探讨如何在Android中有效地处理GIF,以避免OOM问题。 一、GIF的内存占用问题 GIF是一种基于帧的图像格式,每一帧都是一个完整的图像。当在Android中加载GIF时,如果不做特殊处理,所有帧都会被加载到...
在安卓系统中,"OOM"(Out of Memory)是指应用程序因为消耗了过多的内存而被系统强制终止,这是安卓开发者需要特别关注的问题。本篇将深入探讨安卓内存OOM的分析和解决策略,以及如何通过内核剖析来预防和处理此类...
为了解决这个问题,我们需要掌握一些有效的策略来优化图片加载,防止OOM的发生。以下是一些关键知识点: 1. **图片大小与分辨率**:理解图片的像素大小和分辨率至关重要。高分辨率的图片会占用更多内存,因此,尽量...
在Android开发中,"OOM"(Out of Memory)是一个常见的问题,它指的是应用程序在运行过程中耗尽了可用的内存,导致系统无法分配更多的内存资源,从而引发崩溃。为了解决这个问题,开发者需要深入理解Android内存管理...