博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JVM内存溢出分析-实战JVM(二)
阅读量:6440 次
发布时间:2019-06-23

本文共 3631 字,大约阅读时间需要 12 分钟。

  hot3.png

JVM规范规定,除了程序计数器,虚拟机其他内存区域均会发生内存溢出的可能,OutOfMemoryError(OOM)

原文地址:  我的网站,欢迎大家多提意见

本文目的:

    1、通过代码人为造成OOM,让大家跟了解JVM运行时各区存储的内容。

    2、通过demo让大家实际开发过程中,能够根据异常判断是那个内存区域发生的溢出,

    3、让大家了解到什么样的代码会产生OOM,开发中能够尽量规避。

前提:

     先和大家介绍一下eclipse如何设置JVM参数,Xms 最小堆内存,Xmx最大堆内存,

      HeapDumpOnOutOfMemoryError:发生内存溢出时生成堆转储快照

09172510_jmh4.jpg

一、JAVA堆内存溢出

 代码实例,来自<<深入理解JVM虚拟机>>

public class TestOOM {	static class OOMObject{			}	public static void main(String[] args) {		List
list = new ArrayList
(); while(true){ list.add(new OOMObject()); } }}

运行结果如下,发生内存溢出,在OutOfMemoryError后面会跟着 Java heap space 提示是堆内存溢出,

同时生成 java_pid10308.hprof 文件

该文件可以用分析工具MAT进行分析,安装链接 也可以用其他工具,

java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid10308.hprof ...Heap dump file created [27883798 bytes in 0.497 secs]

通过工具可以分析是内存泄露还是内存溢出,如果不存在泄露,那就是存在着很多对象实例无法回收,可以通过分析查看是那些对象,是否必须存活,如果必须存活在考虑适当调整JVM堆参数,如Xmx Xms等在以后的文章中会在此介绍。

二、虚拟机栈和本地方栈溢出(栈溢出)

    1、虚拟机栈

   虚拟机栈溢出,理论上分为两种,一种是线程请求的栈深度大于虚拟机允许的最大深度,另外一种是申请的空间不足。

   因为虚拟机栈记录的是局部变量(方法变量)和函数调用栈针,则产生堆栈溢出一般是函数调用深度,如递归类或者

    方法A调用方法B,方法B调用方法C这样调用深度超过了虚拟机允许的最大深度,

    JVM参数设置为如下,Xss128k  Xss是堆栈大小

-Xms20m -Xmx20m -Xss128k -XX:+HeapDumpOnOutOfMemoryError

 demo如下

public class TestOOM {	static int stackIndex = 0;	public   void testStackOverFlow(){		stackIndex++;		testStackOverFlow();	}	public static void main(String[] args) throws Throwable  {		try{			TestOOM oom = new TestOOM();			oom.testStackOverFlow();		}catch(Throwable e){			System.out.println("堆栈深度(迭代次数):"+stackIndex);			throw e;		}	}}

执行结果,堆栈深度达到983,堆栈溢出,并会给出具体是类,方法,发生的错误

堆栈深度(迭代次数):983Exception in thread "main" java.lang.StackOverflowError	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:10)
相同参数情况下如果修改递归的方法,在方法内创建几个变量大家再看下结果。
public   void testStackOverFlow(){		stackIndex++;		int str = 12;		int str2 = 12;		int str3 = 12;		int str4 = 12;		int str5 = 12;		int str6 = 12;		int str7 = 12;		int str8 = 12;		testStackOverFlow();	}

执行结果如下,迭代次数明显减少,说明局部变量占用了堆栈的空间

堆栈深度(迭代次数):579Exception in thread "main" java.lang.StackOverflowError	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:18)

    2、本地方法栈,本地方法栈可以通过创建线程的方式来实现溢出,因为java线程是映射到操作系统内核上,所以线程会调用本地方法,造成本地方法栈的溢出

   本机环境没测试出来,机器卡死了,大家可以自己试试尽量多创建线程,就会撑爆本地方法栈

   下面是找来的例子,没见到效果,都死卡死机告终

public class Test {	private void runAlways(){		while(true){					}	}	public void createThread(){		while(true){			Thread thread = new Thread(new Runnable(){				public void run() {					runAlways();				}							});			thread.start();		}	}	public static void main(String[] args) {		Test test = new Test();		test.createThread();	}	}

三、直接本机内存溢出

    本机内存溢出可以无限制申请空间即可,用nio的申请缓冲区方式

public static void main(String[] args) {		List list = new ArrayList();		while(true){			ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024*2048);			list.add(byteBuffer);		}	}

执行结果如下,OutOfMemoryError后面的提示,Direct buffer memory 说明了直接缓冲区,

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory	at java.nio.Bits.reserveMemory(Bits.java:658)	at java.nio.DirectByteBuffer.
(DirectByteBuffer.java:123)

四、方法区(永久代)溢出

    方法区存储的是加载的类信息,常量,我们就循环创建字符串常量,让方法区溢出

    为了尽快溢出,jvm参数设置永久代参数5M: -XX:PermSize=5m  -XX:MaxPermSize=5m

    代码如下:

public static void main(String[] args) {		List list = new ArrayList();		int i = 0;		while(true){			list.add((String.valueOf(i++)).intern());		}	}

 运行结果如下:OutOfMemoryError后面提示 PermGen space ;改代码在jdk6及以下版本能够报出如下异常,jdk7高版本及以上部分jvm已经逐渐开始取消永久代的原因,只会报出堆内存异常

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space	at java.lang.String.intern(Native Method)	at com.TestSocket.main(TestSocket.java:12)

转载于:https://my.oschina.net/UpBoy/blog/514926

你可能感兴趣的文章
解决win10不能安装NVIDIA的RTX 20系列的显卡驱动问题
查看>>
pdf如何解密
查看>>
×××S 2012 聚合函数 -- 介绍
查看>>
linux 防火墙 iptables 允许 某个 某段 IP访问 某个端口
查看>>
Open*** 安装脚本
查看>>
计算任意两个数之间1出现的次数的思维过程
查看>>
Error No matching provisioning profiles found
查看>>
windows 2008创建群集“xxx”时出错。由于超时时间已过,该操作返回
查看>>
WinForm 入口Main方法
查看>>
SQL基础语句
查看>>
java算法2_二分查找法
查看>>
MySQL 5.6 & 5.7最优配置文件模板
查看>>
ffmpeg 怎么用
查看>>
JSP中 request.getRealPath("/xx/yy") 方法提示已经过时的替代方法
查看>>
实战 MDT 2012(六)---基于MAC地址的部署
查看>>
下载视频的一种简便方法
查看>>
C#中所有对象共同的基类是System.Object
查看>>
[鸟哥linux视频教程整理]04_02_Linux 权限及权限管理
查看>>
Linux运维工程师面试题第三套
查看>>
商务智能的需求驱动
查看>>