`
noble510520
  • 浏览: 53631 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

jvm内存溢出分析

阅读更多

概述

jvm中除了程序计数器,其他的区域都有可能会发生内存溢出

内存溢出是什么?

当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出

内存溢出和内存泄漏有什么区别?

内存泄漏是由于使用不当,把一部分内存“丢掉了”,导致这部分内存不可用。 
当在堆中创建了对象,后来没有使用这个对象了,又没有把整个对象的相关引用设为null。此时垃圾收集器会认为这个对象是需要的,就不会清理这部分内存。这就会导致这部分内存不可用。 
所以内存泄漏会导致可用的内存减少,进而会导致内存溢出

用到的jvm参数

下面为了说明溢出的情景,会执行一些实例代码,同时需要给jvm指定参数 
- -Xms 堆最小容量(heap min size) 
- -Xmx 堆最大容量(heap max size) 
- -Xss 栈容量(stack size) 
- -XX:PermSize=size 永生代最小容量 
- -XX:MaxPermSize=size 永生代最大容量

堆溢出

堆是存放对象的地方,那么只要在堆中疯狂的创建对象,那么堆就会发生内存溢出。


下面做一个堆溢出的实验 
执行这段代码的时候,要给jvm指定参数

 

//jvm参数:-Xms20m -Xmx20m
public class HeapOOMTest {
	public static void main(String[] args){
		LinkedList<HeapOOMTest> l=new LinkedList<HeapOOMTest>();//作为GC Root
		while(true){
			l.add(new HeapOOMTest());//疯狂创建对象
		}
	}
}

-Xms20m -Xmx20m作用是将jvm的最小堆容量和最大堆容量都设定为20m,这样就不会动态扩展jvm堆了 

这段代码疯狂的创建对象,虽然对象没有声明变量名引用,但是将对象添加到队列l中,这样队列l就持有了一份对象的引用 
通过可达性算法(jvm判断对象是否可被收集的算法)分析,队列l作为GC Root,每一个对象都是l的一个可达的节点,所以疯狂创建的对象不会被收集,这就是内存泄漏,这样总有一天堆就溢出了。


运行结果:

 

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.LinkedList.linkLast(Unknown Source)
	at java.util.LinkedList.add(Unknown Source)
	at test.HeapOOMTest.main(HeapOOMTest.java:23)

 

 

程序发生内存溢出,并提示发生在Java heap space

分析解决方法

思路

visualVM工具分析堆快照 
如果发生内存泄漏: 
step1:找出泄漏的对象 
step2:找到泄漏对象的GC Root 
step3:根据泄漏对象和GC Root找到导致内存泄漏的代码 
step4:想法设法解除泄漏对象与GCRoot的连接 
如果不存在泄漏
1. 看下是否能增大jvm堆的最大容量 
2. 优化程序,减小对象的生命周期

前期准备

当发生堆溢出的时候,可以让程序在崩溃时产生一份堆内存快照 
产生堆内存快照的方法: 
给jvm加上参数XX:+HeapDumpOnOutofMemoryError,这样就会在程序崩溃的时候,产生一份堆内存快照 
分析堆内存快照我建议用jdk自带的可视化监视工具visualVM,位置在jdk安装目录下的bin,如果是在Linux环境的话,可以把快照传到window。因为分析工具会占用很大的内存,不建议在服务端进行分析。

实战

下面对刚才程序产生的堆内存快照进行分析。 
打开visualVM,装入刚刚生成的快照,打开类标签页 
image 
队列和疯狂创建的对象几乎占满了整个栈,想要让垃圾收集器回收这些对象,要让他们与GC Root断开连接 
双击HeapOOMTest类,跳转到实例标签页,可以查看这个类的所有实例 
在实例上右键——显示最近的垃圾回收根节点,可以看到这个对象与根节点的连接 
image 
只要断开HeapOOMTest对象与LinkedList的连接,这些疯狂创建的对象就会被收集了

栈溢出

调用方法的时候,会在栈中入栈一个栈帧,如果当前栈的容量不足,就会发生栈溢出StackOverFlowError 
那么只要疯狂的调用方法,并且有意的不让栈帧出栈就可以导致栈溢出了。


下面来一次栈溢出

 

//jvm参数:-Xss128k
public class StackSOFTest {
	public void stackLeak(){
		stackLeak();//递归,疯狂的入栈,有意不让出栈
	} 
	public static void main(String[] args){
		StackSOFTest s=new StackSOFTest();
		s.stackLeak();
	}
}

 

 

jvm设置参数-Xss128k,目的是缩小栈的空间,这样栈溢出“来的快一点” 

程序中用了递归,让栈帧疯狂的入栈,又不让栈帧出栈,这样就会栈溢出了。


运行结果:

 

Exception in thread "main" java.lang.StackOverflowError
	at test.StackSOFTest.stackLeak(StackSOFTest.java:17)
	at test.StackSOFTest.stackLeak(StackSOFTest.java:17)

运行时常量池溢出

这里储存的是一些常量、字面量。如果运行时常量池内存不足,就会发生内存溢出。从jdk1.7开始,运行时常量池移动到了堆中,所以如果堆的内存不足,也会导致运行时常量池内存溢出。


下面来一次运行时常量池溢出,环境是jdk8 
只要创建足够多的常量,就会发生溢出

 

/**
 * jvm参数:
 * jdk6以前:-XX:PermSize=10M -XX:MaxPermSize=10M
 * jdk7开始:-Xms10m -Xmx10m
 * */
public class RuntimePoolOOM {
	public static void main(String[] args){
		int i=1;
		LinkedList<String> l=new LinkedList<String>();//保持常量的引用,防止被fullgc收集
		while(true){
			l.add(String.valueOf(i++).intern());//将常量添加到常量池
		}
	}
}

 

 

因为jdk6以前,运行时常量池是在方法区(永生代)中的,所以要限制永生代的容量,让内存溢出来的更快。 

从jdk7开始,运行时常量池是在堆中的,那么固定堆的容量就好了 
这里用了链表去保存常量的引用,是因为防止被fullgc清理,因为fullgc会清理掉方法区和老年代 
intern()方法是将常量添加到常量池中去,这样运行时常量池一直都在增长,然后内存溢出


运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.lang.Integer.toString(Unknown Source)
	at java.lang.String.valueOf(Unknown Source)
	at test.RuntimePoolOOM.main(RuntimePoolOOM.java:30)

提示在heap区域发生内存溢出,果然运行时常量池被移到了堆中

方法区溢出

方法区是存放类的信息,而且很难被gc,只要加载了大量类,就有可能引起方法区溢出 
这里将不做演示了,想试试的可以用cglib创建大量的代理类

分析

工作中也有可能会遇上方法区溢出: 
当多个项目都有相同jar包的时候,又都存放在WEB-INF\lib\下,这样每个项目都会加载一遍jar包。会导致方法区中有大量相同类(被不同的类加载器所加载),又不会被gc掉。

解决方案:

  1. 在应用服务器中建立一个共享lib库,把项目中常用重复的jar包存放在这里,项目从这里加载jar包,这样就会大大减少类加载的数量,方法区也“瘦身”了
  2. 如果实在不能瘦身类的话,那可以扩大方法区的容量,给jvm指定参数-XX:MaxPermSize=xxxM

查看原文:http://blog.zswlib.com/2016/11/07/jvm%e5%86%85%e5%ad%98%e6%ba%a2%e5%87%ba%e5%88%86%e6%9e%90/
0
5
分享到:
评论

相关推荐

    JVM原理及内存溢出经典案列分析.ppt

    简单的判断JVM内存溢出的方法

    关于JVM内存溢出的原因分析及解决方案探讨.docx

    关于JVM内存溢出的原因分析及解决方案探讨.docx

    jvm内存分析工具mat安装包

    JVM内存dump分析工具MAT独立安装包,分析内存溢出利器,可以准确定位内存异常原因,解决问题,MemoryAnalyzer-1.10.0.20200225.zip

    JVM原理及内存溢出案列分析PPT教案学习.pptx

    JVM原理及内存溢出案列分析PPT教案学习.pptx

    JVM 精华知识点汇总1

    前言文章对 JVM 内存区域分布、JVM 内存溢出分析、JVM 垃圾回收算法/垃圾收集器、JVM 性能调优工具及技巧、类加载等部分做了详细描述。用XMind画了

    JVM内存分析

    主要是针对JVM内存溢出,服务器宕机,内存优化,溢出类型进行介绍

    某应用内存溢出(暨jvm)分析分享

    NULL 博文链接:https://xinglijun1973.iteye.com/blog/2372834

    使用JNA替代JNI调用DLL,并解决内存溢出问题

    在开发项目过程中,需要处理算法分析出来二进制流数据,并对数据解析处理转发。我们上层应用平台是使用java开发的,但开放平台是使用c++开发,虽提供给我们对应的.h头文件,但在java中来解析这些数据就显然有些复杂...

    JVM内存分析工具HeapAudit.zip

    而阻碍系统性能提高的第一大元凶就是内存问题,更糟糕的是如果GC不能完全释放无用的内存,这会导致内存溢出,从而产生更严重的后果。 找出内存问题的元凶是一件非常困难的任务,幸运的是,heapaudit可以解决这个问题...

    JVM实战篇笔记.pdf

    JVM实战篇笔记,提供全方面的JVM 操作教程,定位JVM 内存溢出,堆栈使用情况,内存溢出分析,在线基于工具实时监控

    Tomcat内存溢出的三种情况及解决办法分析

    Tomcat内存溢出的三种情况及解决办法分析 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内存原因是不一样的,当然处理方式也不一样。 这里根据平时遇到的情况和相关资料进行一个...

    idea git提交内存溢出后dump文件

    今天在idea中 git commit&pull的时候,手快不知道点了什么,窗口被关了,然后发现commit了未提交,点击pull,内存溢出了,留下dump后的文件,以后有能力了再分析

    was内存溢出分析工具jca401

    The code that creates Javacore is part of the JVM. You can control it by using environment variables and runtime switches. Javacore contains diagnostic information related to the JVM and a Java ...

    Java-JVM优化视频.zip

    4 jmap的使用以及内存溢出分析 5 实战:内存溢出的定位与分析 6 jstack的使用 7 VisualVM工具的使用 day2: 1 什么是垃圾回收 2 垃圾回收的常见算法 3 垃圾收集器以及内存分配 4 可视化GC日志分析工具 day3: 1 ...

    Tomcat内存溢出分析及解决方法

    堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的,本文将详细介绍Tomcat内存溢出,需要了解更多的朋友可以参考下

    深入理解JVM内存结构及运行原理全套视频加资料.txt

     第4讲 jvm初体验-内存溢出问题的分析与解决 免费 00:17:59  第5讲 jvm再体验-jvm可视化监控工具 免费 00:21:17  第6讲 杂谈 免费 00:12:37  第7讲 Java的发展历史 00:27:24  第8讲 Java的发展历史续 00:...

    JVM基础知识及分析工具

    一、Jdk组成 二、Jdk32与jdk64的差异 三、自动内存管理机制 四、内存泄露与内存溢出 五、垃圾回收算法 六、虚拟机性能监控工具

    Java进阶教程解密JVM视频教程

    * 在内存结构章节,能够学习掌握 JVM内存溢出现象,堆栈内存结构,利用内存诊断工具排查问题。彻底分析 StringTable的相关知识与性能优化,掌握直接内存分配原理和释放手段。 * 在垃圾回收章节,不仅会介绍垃圾回收...

    IBM HeapAnalyzer

    jvm java oom分析 OutOfMemory 内存溢出分析工具

    JVM优化|java虚拟机优化

    - 掌握定位分析内存溢出的方法 - 掌握jstack命令的使用 - 掌握VisualJVM工具的使用 - 了解什么是垃圾回收 - 掌握垃圾会回收的常见算法 - 学习串行、并行、并发、G1垃圾收集器 - 学习GC日志的可视化查看 - Tomcat8的...

Global site tag (gtag.js) - Google Analytics