Java虚拟机3:内存溢出
1.前言
上一篇我们介绍了java的内存区域结构,这一篇,模拟内存溢出的几个场景,下面一个图是总体的指导思想:
2.Java堆溢出
Java堆唯一的作用就是存储对象实例,只要保证不断创建对象并且对象不被回收,那么对象数量达到最大堆容量限制后就会产生内存溢出异常了。所以测试的时候把堆的大小固定住并且让堆不可扩展即可。测试代码如下:
1 package com.xrq.test;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * 测试内容:堆溢出
8 *
9 * 虚拟机参数:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
10 */
11 public class HeapOverflowTest
12 {
13 public static void main(String[] args)
14 {
15 List<HeapOverflowTest> list = new ArrayList<HeapOverflowTest>();
16 while (true)
17 {
18 list.add(new HeapOverflowTest());
19 }
20 }
21 }
运行结果
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid8876.hprof ...
Heap dump file created [15782068 bytes in 0.217 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2760)
at java.util.Arrays.copyOf(Arrays.java:2734)
at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
at java.util.ArrayList.add(ArrayList.java:351)
at com.xrq.test.HeapOverflowTest.main(HeapOverflowTest.java:18)
这种异常很常见,也很好发现,因为都提示了“Java heap space”了,定位问题的话,根据异常堆栈分析就好了,行号都有指示。
解决方案:可以调大堆的大小或者从代码上检视是否存在某些对象生命周期过长、持有状态时间过长的情况,长时间减少程序运行期间的内存消耗。
另外,由于Java堆内也可能发生内存泄露(Memory Leak),这里简要说明一下内存泄露和内存溢出的区别:
内存泄露:是指分配出去的内存没有被回收回来,由于失去了对该内存区域的控制,因而造成了资源的浪费。Java中一般不会产生内存泄露,因为有垃圾回收器自动回收垃圾,但这也不绝对,当我们new了对象,并保存了其引用,但是后面一直没用它,而垃圾回收器又不会去回收它,这边会造成内存泄露,
内存溢出:是指程序所需要的内存超出了系统所能分配的内存(包括动态扩展)的上限。
3.方法区和运行时常量池溢出
运行时常量池也是方法区的一部分,所以这两个区域一起看就可以了。这个区域的OutOfMemoryError可以利用String.intern()方法来产生。这是一个Native方法,意思是如果常量池中有一个String对象的字符串就返回池中的这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中去,并且返回此String对象的引用。测试代码如下:
1 package com.xrq.test;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * 测试内容:常量池溢出(这个例子也可以说明运行时常量池为方法区的一部分)
8 *
9 * 虚拟机参数-XX:PermSize=10M -XX:MaxPermSize=10M
10 */
11 public class ConstantPoolOverflowTest
12 {
13 public static void main(String[] args)
14 {
15 List<String> list = new ArrayList<String>();
16 int i = 0;
17 while (true)
18 {
19 list.add(String.valueOf(i++).intern());
20 }
21 }
22 }
运行结果
Exception in thread "Reference Handler" Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at com.xrq.test.ConstantPoolOverflowTest.main(ConstantPoolOverflowTest.java:19)
java.lang.OutOfMemoryError: PermGen space
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:123)
之前有讲过,对于HotSpot而言,方法区=永久代,这里看到OutOfMemoryError的区域是“PermGen space”,即永久代,那其实也就是方法区溢出了。注意一下JDK1.7下是不会有这个异常的,while循环将一直下去,因为JDK1.7之后溢出了永久代并采用Native Memory来实现方法区的规划了。
4.栈溢出
Java虚拟机规范中描述了如果线程请求的栈深度太深(换句话说方法调用的深度太深),就会产生栈溢出了。那么,我们只要写一个无限调用自己的方法,自然就会出现方法调用的深度太深的场景了。测试代码如下
1 package com.xrq.test;
2
3 /**
4 * 测试内容:栈溢出测试(递归调用导致栈深度不断增加)
5 *
6 * 虚拟机参数:-Xss128k
7 */
8 public class StackOverflowTest
9 {
10 private int stackLength = 1;
11
12 public void stackLeak()
13 {
14 stackLength++;
15 stackLeak();
16 }
17
18 public static void main(String[] args) throws Throwable
19 {
20 StackOverflowTest stackOverflow = new StackOverflowTest();
21 try
22 {
23 stackOverflow.stackLeak();
24 }
25 catch (Throwable e)
26 {
27 System.out.println("stack length:" + stackOverflow.stackLength);
28 throw e;
29 }
30 }
31 }
运行结果:
stack length:1006
Exception in thread "main" java.lang.StackOverflowError
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:14)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
at com.xrq.test.StackOverflowTest.stackLeak(StackOverflowTest.java:15)
...
多线程:这里需要注意一下多线程的情况,多线程下通过不断创建线程的方式,可以产生OutOfMemoryError异常,因为每个线程都有自己的栈空间,栈空间越大,越容易产生内存溢出异常。其实这也很好理解,操作系统分配给进程的内存是有限制的,比如32位的Windows限制为2GB。虚拟机提供了了参数来控制Java堆和方法区这两部分内存的最大值,剩余内存为2GB-最大堆容量-最大方法区容量,程序计数器很小就忽略了,虚拟机进程本身的耗费也不算,剩下的内存就是栈的了。每个线程分配到的栈容量越大,可建立的线程数自然就越少,建立线程时就越容易把剩下的内存耗尽,可能造成操作系统的假死。
多线程导致的OutOfMemoryError,在不能减少线程数的情况下,就只能通过减少最大堆和每个线程的栈容量来换取更多的线程了。
单线程:StackOverFlowError这个异常,有错误堆栈可以阅读,比较好定位。而且如果使用虚拟机默认参数,栈深度在大多数情况下,达到1000~2000完全没有问题,正常方法的调用这个深度应该是完全够了。
转载地址:http://www.cnblogs.com/xrq730/p/4833713.html
http://blog.csdn.net/ns_code/article/details/17565503
Java虚拟机3:内存溢出的更多相关文章
- 深入理解java虚拟机【内存溢出实例】
通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...
- 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码
程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...
- java虚拟机涉及内存溢出
Java语言写的代码是.java文件,它会被特定程序编译(javac.exe,它会被Eclipse之类的IDE调用)成字节码(bytecode),字节码不能直接在CPU上运行,需要另一个程序读取并执行 ...
- Java 虚拟机的内存溢出
在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能. 在Eclipse中进行JVM参数设置 可以直接通过上方菜单栏的 ...
- java虚拟机(四)--内存溢出、内存泄漏、SOF
学习了java运行时数据区,知道每个内存区域保存什么数据,可以参考:https://www.cnblogs.com/huigelaile/p/diamondshine.html,然后了 解内存溢出和内 ...
- 【java虚拟机】内存溢出与内存泄漏
作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/7354857.html 一.基本概念 内存溢出:简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提 ...
- 【java虚拟机】内存溢出解决思路
转自:https://blog.csdn.net/u013521220/article/details/79523633 内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知 ...
- (一)深入java虚拟机之内存溢出与分析
一.内存溢出程序 public class Test { public static void main(String[] args) { List<User> userList=new ...
- 实战Java虚拟机之一“堆溢出处理”
从今天开始,我会发5个关于java虚拟机的小系列: 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Java虚拟机之四 ...
- 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制
一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...
随机推荐
- Mongodb定时备份脚本和清除脚本
Mongodb用的是可以热备份的mongodump和对应恢复的mongorestore,在linux下面使用shell脚本写的定时备份,代码如下 1.定时备份 #!/bin/bash sourcepa ...
- IE浏览器报Promise未定义
用vue-cli做的项目,用了promise,结果IE下报promise未定义,甚至在比较老的andriod手机浏览器上会显示空白页面,解决方案如下: 首先安装:babel-polyfill npm ...
- nginx启动,停止,重启
Nginx的启动.停止与重启 启动 启动代码格式:nginx安装目录地址 -c nginx配置文件地址 例如: [root@LinuxServer sbin]# /usr/local/nginx/ ...
- 「Sdchr 的邀请赛」题解
骗个访问量.. A:取石子 将点 x 与点 x / prime 连边,那么这个图可以由指数之和的奇偶性来划分成一个二分图. 接下来考虑推广阶梯 NIM (或者这原本就是阶梯 NIM ?),必胜当且仅当 ...
- Codeforces 936E. Iqea
Description 给出一张四连通网格图,其中有 \(n\) 个点是连通的,维护以下两种操作: 1.把某个点变黑 2.给出一个白点,查询离这个白点最近的黑点的距离 题面 Solution 我们把每 ...
- jQuery ajax async
jQuery 同步调用: jQuery.ajax({ type:'POST', async: false, url:'qcTask/add', contentType:'application/jso ...
- zookeeper【6】负载均衡
负载均衡是一种手段,用来把对某种资源的访问分摊给不同的设备,从而减轻单点的压力. 架构图 图中左侧为ZooKeeper集群,右侧上方为工作服务器,下面为客户端.每台工作服务器在启动时都会去zookee ...
- Alice's Print Service
Alice's Print Service Time Limit: 2 Seconds Memory Limit: 65536 KB Alice is providing print ser ...
- php FastCGI 进程意外退出 错误解决方法
服务器windows2008,php5.5 / php5.6,需要安装VC++运行库. 到Microsoft网站下载“Microsoft Visual C++ 2012 Redistributable ...
- linux cut: invalid byte, character or field list Try 'cut --help' for more information.
1. 概述 centos执行简单shell 脚本 报错 cut: invalid byte, character or field listTry 'cut --help' for more info ...