记一次内存溢出查找分析文档

Posted 诗萧尘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次内存溢出查找分析文档相关的知识,希望对你有一定的参考价值。

内存溢出介绍。

内存溢出和内存泄漏的联系:
内存泄漏会最终导致内存溢出。
相同点:都会导致应用程序运行出现问题,性能下降或挂起。
不同点:
1 内存泄漏是导致内存溢出的原因之一,内存泄漏积累起来导致内存溢出。
2 内存泄漏可以通过完善代码来避免,内存溢出可以通过调整完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

内存溢出

内存溢出 (out of memory),是指程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory ;
比如申请了一个integer,但给它存了long才能存下的数。
产生原因 :
1内存中加载的数据量过于庞大,如一次从数据库取出过多的数据。(主要排查方式 导出,导入。以及排查未分页的查询:表现为对应web页面假死。)
2 JVM 启动参数内存值设定的过小。
3使用的第三方软件中的BUG。

内存泄漏

内存泄漏 (memory leak),是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏危害可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟早会被占光。Memory leak 最终会导致 out of memory。
内存泄漏对象特点:
1 这些对象是可达的,即在有向图中,存在通路可以与其相连;
2 这些对象是无用的,程序以后不会在使用这些对象。
对象满足这两个条件,可以判定位Java 中的内存泄漏,这些对象不会被GC 所回收。
产生原因:
1 集合类中有对对象的引用,使用完未清空,使得JVM不能回收。
2 代码中存在死循环或循环产生过多重复的对象实体;
3 使用的第三方软件中的BUG。

JVM内存介绍

主要分为 head (堆)和 Non-head(非堆)
Head(堆):
是JVM 的内存数据区,是被所有线程共享的内存区域,在JVM启动时进行创建。是垃圾回收的主要场所。
存放所有的对象实例,和数组。
分为新生代和老年代:新生代用于存放刚创建的对象以及年轻的对象,如果对象一直没有被回收,生存得足够长,对象就会被移入老年代。
这里主要的情形是使用反射动态的生成对象的实例。
Non-head(非堆)
主要放置 类,方法的定义,方法的参数、局域变量的引用,方法执行顺序按照栈的先入后出方式。

JVM 虚拟机内存处理方式

JVM参数介绍:
-XX:+PrintGCDetails 打印垃圾回收信息(怎么打印?)
-Xms: head 区域的初始值,线上环境需要与Xmx 设置为一致,否则capacity 的值会来回飘动。(capacity 是指的啥)
-Xmx : head 的最大值
-Xss(或-ss) 线程栈大小(指一个线程的native 空间)1.5 以后是 1M 的默认大小
-XX:PermSize 与 –XX:MaxPermSize 方法区(永久代)的初始大小和最大值(但不是本地方法区)
-XX: NewRatioa 老年代与新生代比率。
-XX:SurvivorRatio Eden 与 Survivor 的占用比例。
例子 8 表示, 一个survivor区占用1/8的Eden内存,即1/10的新生代内存,为什么不是1/9?因为我们的新生代有2个survivor,即S1和S22.所以survivor 总共是占用新生代内存的2/10 ,Eden与新生代的占比为8/10.
-XX:MaxHeapFreeRatio GC 后,如果发现空闲堆内存占到整个预估的比例小于这个值,则减少堆空间。
-XX:NewSize 新生代大小。
官方给出的堆内存分配方式
默认空余堆内存小于 40% 时,JVM 就会增大堆直到-Xmx的最大限制。空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制

内存溢出报错简介。

PermGen space

程序中使用了大量的jar 或class,使JVM 装载类的空间不够,与Permanent Generation space 有关。
解决方案:
改变 XX:MaxPermSize
XX:PermSize 的大小。
例子
comcat 在 catalina.sh 或 catalina.bat
大约在 70行左右
增加一行
JAVA_OPTS= “ -XX:PermSize=64M –XX:MaxPermSize=256m ”
Eclipse
-Xms512m -Xmx512m -XX:PermSize=64M -XX:MaxPermSize=256m

Java heap space

在进行垃圾回收之前,JVM 分配的到堆内存空间已经满了,与heap space 有关。可用的 head size 不足 2% 时候抛出此类异常。
检查程序:
看是否有死循环或不必要地重复创建大量对象。
增加Java 虚拟机中Xms 和Xmx 参数的大小。

Unable to create new native thread

因为JVM已经被系统分配了大量的内存,并且它至少要占用可用内存的一半,在线程个数很多的情况下,你分配给JVM 的内存越多,此错误发生的可能性越大。
主要发生在 32 位系统中,每个32 位的进程最多使用2G的可用内存。
简单解释:
假设分给JVM 1.5 G 内存,余下500M可用内存。这500M内存中的一部必须用于系统dll 的加载,也许真正剩下的 400 M ,关键的地方出现了,当使用 java 创建一个线程,在JVM的内存里也会创建一个Thread对象,但是同时也会在操作系统里创建一个真正的物理线程,操作系统会在余下的400M 内存里创建这个物理线程,而不是在JVM 的 1500 M 的内存堆里创建。在 jdk1.4 里,默认栈的大小是256 KB。在jdk1.5 里,默认栈大小 1M /线程。 在余下的400M 内存最多也只能创建400 个可用线程。

内存溢出代码排查方法。

Connect

数据库连接排查,主要代码开连接和关闭连接
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
这里面需要先关 rs 在关 stmt ,在关 conn
不能只关闭conn ,会导致 rs,stmt 在内存中一致占用。rs 也必须主动释放。
代码:

finally 
			              // 关闭链接
			                  JdbcUtil.close(rs, null, conn);
		                          
public static void close(ResultSet rs, Statement ps, Connection conn) 
	if (rs != null) 
		try 
			rs.close();
		 catch (SQLException e) 
			log.error("ResultSet¹Ø±Õ´íÎó"+e);
		
	
	if (ps != null) 
		try 
			ps.close();
		 catch (SQLException e) 
			log.error("Statement¹Ø±Õ´íÎó"+e);
		
	
	if (conn != null) 
		try 
			conn.close();
		 catch (SQLException e) 
			log.error("Connection¹Ø±Õ´íÎó"+ e);
		
	

Stream

主要方法未 Ctrl + H 在 java 搜索 stream。
找到未关闭的流,在finally 中关闭。
代码:

    FileInputStream in =  null;
    ByteArrayOutputStream bout = null;
finally 
       	try 
			if(bout!=null)
			bout.close();
			if(in!=null)
			in.close();
			if(out!=null)
				out.flush();
				out.close();
			
		 catch (Exception e) 
			e.printStackTrace();
		
    

导出/导入

如果导出/导入的数量量巨大,是导致内存溢出主要原因。
参考:
1个汉字=2B
1个字母/数字 = 1B
1KB =1024B
1MB=1024KB
1GB=1024MB
计算时:考虑 导入数量,同时导入人数。
例子: 场景客户群导入,导入字段3个。导入10000条,100人同时使用。

字段长度
CUST_ID30 B
CUST_ZH_NAME10 B
CUST_ID30 B
CUST_BASE_ID30 B
一条数据70B
10000条683.59KB=0.667MB
100人同时使用66.7MB

结论:对堆内存几乎没有影响。

固定类

   固定类的查找,会发生内存泄漏的。
   结合具体业务逻辑。

感谢支持~

thanks~

以上是关于记一次内存溢出查找分析文档的主要内容,如果未能解决你的问题,请参考以下文章

记一次 .NET 某妇产医院 WPF内存溢出分析

记一次内存溢出的分析经历 : thrift 带给我的痛

记一次内存溢出的分析经历——thrift带给我的痛orz

JVM记一次PermGen space内存溢出实战案例

记一次使用Memory Analyzer工具分析堆内存溢出问题

记一次java内存溢出的解决过程