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自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...
随机推荐
- jquery清空下拉框,保留第一个
js中可以document.getElementById("id").options.length = 1;设置 jquery中的设置方法:$("#id option[i ...
- Windows开启telnet命令
1.点击开始 → 运行 → 输入telnet,回车. 2.点击启用或关闭Windows功能 3.找到Telnet客户端,勾选,点击确认 4.搞定,测试一下 打开CMD,在出来的DOS界面里,输入tel ...
- 文档转换为pdf格式帮助类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Word = M ...
- Nginx配置整理
不论是本地开发,还是远程到 Server 开发,还是给提供 demo 给人看效果,我们时常需要对 Nginx 做配置,Nginx 的配置项相当多,如果考虑性能配置起来会比较麻烦.不过,我们往往只是需要 ...
- OC与JS交互之JavaScriptCore
JavaScriptCore提供了JavaScript和Objective-C桥接的Obj-C API.JavaScriptCore提供了让我们脱离UIWebView执行JavaScript脚本的能力 ...
- [转]ubuntu 13.04 体验wine qq
1.首先安装最新版的wine1.52,没记错版本号应该是这个 sudo add-apt-repository ppa:ubuntu-wine/ppa sudo apt-get update sudo ...
- linux 忘记密码
密码保存在/etc/shadow文件中 1. root 密码忘记了 1.1 重启进入单人维护模式后, 系统会主动给予root权限的bash接口, 此时再以passwd修改密码即可: 1.2 以Live ...
- 【Udacity】解决:字幕遮挡视频内容怎么办?Udacity字幕大小调整
字幕有没有办法显示在最下方,否则把内容挡住了,根本看不清老师所指的内容 Chrome 的小插件,能方便地调节视频的字幕大小,譬如:Udacity 的学习视频字幕大小不能调节,有时候不想它占太多位置,而 ...
- 【Python】raw转义字符
r"hi" 这里字符串前面加了r,是raw的意思,它表示对字符串不进行转义.为什么要加这个?你可以试试print "\bhi"和r"\bhi" ...
- 添加CentOS扩展源
参考: http://blog.onovps.com/archives/centos-yum-epel.html https://fedoraproject.org/wiki/EPEL/zh-cn h ...