深入理解JVM虚拟机(二):JDK 内存类的异常分析
JVM数据存储
- 堆存储(Heap):对象存储,实际上就是JAVA的数据存储
- 方法堆栈(Method Stack):存储方法调用的关系。
- 永久代(Perm):在JDK1.6及之前,常量数据存储于此区域
异常示例
堆存储异常
package com.wlzjdm.jvm.learning; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; /**
* VM args : -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
* 模拟内存溢出情况,抛出:java.lang.OutOfMemoryError: Java heap space
* 当配置为:[-Xms20m -Xmx20m]时,执行信息:Heap dump file created [27931458 bytes in 0.604 secs],内存中存放了:810325个对象
* 当配置为:[-Xms10m -Xmx10m]时,执行信息:Heap dump file created [13075518 bytes in 0.261 secs],内存中存放了:360145个对象
* 分析.hprof工具为:MemoryAnalyzer
* 结论:
* <li>
* 通过配置-Xms参数设置堆最小值,通过-Xmx设置堆最大值,当堆使用大于最大值得时候就会抛出OutOfMemoryError。
* </li>
* <li>
* 堆是用于存储内存对象的,当我们写代码的时候,生成的每一个对象都会放在堆中。
* </li>
* @author FDD
*
*/
public class HeapOOM {
static class HeapObject implements Serializable{ } public static void main(String[] args) throws Exception {
List<HeapObject> list = new ArrayList<HeapObject>();
try {
//计算一个对象大小。按照序列化方式计算
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(bos);
// oos.writeObject(new HeapObject());
// System.out.println(bos.toByteArray().length);
// oos.close();
// bos.close();
while(true){
list.add(new HeapObject());
}
} catch (Throwable e) {
System.out.println("List size is :" + list.size());
e.printStackTrace();
}
}
}
执行结果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid44464.hprof ...
Heap dump file created [27864823 bytes in 0.523 secs]
List size is :810325
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2245)
at java.util.Arrays.copyOf(Arrays.java:2219)
at java.util.ArrayList.grow(ArrayList.java:213)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
at java.util.ArrayList.add(ArrayList.java:411)
at com.wlzjdm.jvm.learning.HeapOOM.main(HeapOOM.java:42)
方法栈溢出
package com.wlzjdm.jvm.learning; /**
* VM Args: -Xss128K
* 模拟测试本地方法栈溢出情况,抛出:java.lang.StackOverflowError<br>
* <ul>
* 配置为:-Xss1K时,stack大小为19015
* </ul>
* <ul>
* 配置为:-Xss2K时,stack大小为18434
* </ul>
* <ul>
* 配置为:-Xss128K时,stack大小为987
* </ul>
* <ul>
* 配置为:-Xss512K时,stack大小为8486
* </ul>
* <ul>
* 配置为:-Xss1M时, stack大小为19264
* </ul>
* <ul>
* 配置为:-Xss20M时, stack大小为1270590
* </ul>
* <b>结论:</b>
* <li>
* -Xss用于配置本地方法栈大小
* </li>
* <li>
* 栈是方法区使用的,很容易理解,一般一个方法都是后进先出的。
* </li>
* @author FDD
*
*/
public class JavaVMStackESOF {
private int stackLength = 1; public void stackLeak(){
stackLength ++;
stackLeak();
} public static void main(String[] args) throws Throwable {
JavaVMStackESOF javaVMStackESOF = new JavaVMStackESOF();
try {
javaVMStackESOF.stackLeak();
} catch (Throwable e) {
System.out.println("Stack Length is :" + javaVMStackESOF.stackLength);
throw e;
}
}
}
执行结果:
Stack Length is :11429
Exception in thread "main" java.lang.StackOverflowError
at com.wlzjdm.jvm.learning.JavaVMStackESOF.stackLeak(JavaVMStackESOF.java:38)
at com.wlzjdm.jvm.learning.JavaVMStackESOF.stackLeak(JavaVMStackESOF.java:39)
at com.wlzjdm.jvm.learning.JavaVMStackESOF.stackLeak(JavaVMStackESOF.java:39)
at com.wlzjdm.jvm.learning.JavaVMStackESOF.stackLeak(JavaVMStackESOF.java:39)
at com.wlzjdm.jvm.learning.JavaVMStackESOF.stackLeak(JavaVMStackESOF.java:39)
………………
永久代溢出
package com.wlzjdm.jvm.learning; import java.util.ArrayList;
import java.util.List; /**
* VM Args: -XX:PermSize=1M -XX:MaxPermSize=1M <br>
* 说明:此项是配置永久代大小,在JDK1.6及之前,常量是存放于永久代中,所以限制永久代大小就简介限制常量池大小<br>
* <code>
* <b>JDK1.6 Run Result :</b>
* <li>
* Configuration -XX:PermSize=10M -XX:MaxPermSize=10M : 116804 Exception in thread "main" java.lang.OutOfMemoryError: PermGen space <br>
* </li>
* <li>
* Configuration -XX:PermSize=20M -XX:MaxPermSize=20M : 280572 Exception in thread "main" java.lang.OutOfMemoryError: PermGen space <br>
* </li>
* <b>JDK > 1.7 Run Result :</b>
* <li>
* 可以一直运行下去
* </li>
* <b>结论:-XX:PermSize和-XX:MaxPermSzie是配置永久代的大小,在JDK1.6及之前,常量是存放于永久代中,所以可以通过配置永久代大小配置敞亮池,而在JDK1.6之后,逐步剔除永久代的事情。</b>
* </code>
* @author FDD
*
*/
public class RuntimeConstantPoolOOM {
public static void main(String[] args) throws Throwable {
List<String> list = new ArrayList<String>(); int i = 0; try {
while(true){
list.add(String.valueOf(i++).intern());
}
} catch (Throwable e) {
System.out.println(list.size());
throw e;
}
}
}
运行结果:
280572
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at com.wlzjdm.jvm.learning.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:34)
方法区溢出
package com.wlzjdm.jvm.learning; import java.lang.reflect.Method; import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; /**
* VM Args : -XX:PermSize=10M -XX:MaxPermSize=10M <br>
* 此例用来模拟方法区异常,
* 结果:OutOfMemoryError: PermGen space
* @author FDD
*
*/
public class JavaMethodAreaOOM {
public static void main(String[] args) throws Exception {
while (true) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return proxy.invoke(obj, args);
}
});
enhancer.create();
}
} static class OOMObject {
public OOMObject() {
}
}
}
运行结果:
Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:256)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:286)
at com.wlzjdm.jvm.learning.JavaMethodAreaOOM.main(JavaMethodAreaOOM.java:29)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:395)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
... 3 more
Caused by: java.lang.OutOfMemoryError: PermGen space
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
... 8 more
本机内存溢出
package com.wlzjdm.jvm.learning; import java.lang.reflect.Field; import sun.misc.Unsafe; /**
* VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M</br>
* JVM可以通过指定-XX:MaxDirectMemorySize指定,如果不指定,那么默认与JAVA堆最大值-Xmx一样。<br>
* 执行结果:Exception in thread "main" java.lang.OutOfMemoryError
* @author FDD
*
*/
public class DirectMemoryOOM {
private static final int _1MB = 1024 * 1024; public static void main(String[] args) throws Exception {
Field unsaveField = Unsafe.class.getDeclaredFields()[0];
unsaveField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsaveField.get(null);
while(true){
unsafe.allocateMemory(_1MB);
}
} }
运行结果
Exception in thread "main" java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at com.wlzjdm.jvm.learning.DirectMemoryOOM.main(DirectMemoryOOM.java:22)
总结
对于一个内存溢出的问题,我们一定要搞清楚是那块儿内存溢出,只有明白那块内存溢出,才知道系统的数据存储分配,然后通过分析Heap Dump文件得出具体的类,根据错误类型定位到具体的问题点(注意:DirectMemory导致的内存溢出,一个明显的特征是在Heap Dump文件中不会看见明显的异常)。
深入理解JVM虚拟机(二):JDK 内存类的异常分析的更多相关文章
- 深入理解JVM(二)——内存模型、可见性、指令重排序
上一篇我们介绍了JVM的基本运行流程以及内存结构,对JVM有了初步的认识,这篇文章我们将根据JVM的内存模型探索java当中变量的可见性以及不同的java指令在并发时可能发生的指令重排序的情况. 内存 ...
- 深入理解JVM虚拟机-2自动内存管理机制
java虚拟机所管理的内存将会包括一下几个运行时数据区域. 程序计数器: 程序计数器是一块较小的内存空间.字节码解析式工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支.循环.跳转 ...
- 深入理解JVM虚拟机11:Java内存异常原理与实践
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 《深入理解JVM虚拟机》读书笔记
前言:<深入理解JVM虚拟机>是JAVA的经典著作之一,因为内容更偏向底层,所以之前一直没有好好的阅读过.最近因为刚好有空,又有了新目标.所以打算和<构架师的12项修炼>一起看 ...
- Java工程师学习指南第6部分:深入理解JVM虚拟机
本文整理了微信公众号[Java技术江湖]发表和转载过的JVM虚拟机相关优质文章,想看到更多Java技术文章,就赶紧关注本公众号吧吧. JVM原理分析,看了都说好 JVM 深入学习:Java 解析 Cl ...
- 进入JVM的世界:《深入理解JVM虚拟机》-- 思维导图
进入JVM的世界:<深入理解JVM虚拟机>-- 思维导图 之前一直都是零零散散的看了些JVM的知识,心想这样不行啊!于是便抽空看了一下这本神书,阅罢,醍醐灌顶.豁然开朗.真正的是知其然,更 ...
- 《深入理解 java 虚拟机》学习 -- 内存分配
<深入理解 java 虚拟机>学习 -- 内存分配 1. Minor GC 和 Full GC 区别 概念: 新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java ...
- 深入理解JVM(二)JVM内存模型
一.前言 上文讲过了虚拟机的内存划分,即,我们将内存分为线程共享和线程私有. 线程共享的即java堆,和方法区.java堆大家可能都不会陌生:而方法区中包含了常量池,他也被称为永久代.通常方法区也会被 ...
随机推荐
- DevExpress的TreeList实现显示本地文件目录并自定义右键实现删除与重命名文件
场景 使用DevExpress的TreeList显示本磁盘下文件目录并在树节点上右键实现删除与添加文件. 效果 自定义右键效果 实现 首先在包含Treelist的窗体的load方法中对treelist ...
- CronExpression表达式详解和案例
1. cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} 2. cron表达式各占位符解释: {秒数} ==> 允许值范围: 0~59 ,不允许 ...
- 用两种以上的 方式实现一个方法或者对象,调用时打印"你好xx",已定义的代码不能做修改,自己编译的不能出现"你好"? (Javasctript)
先上代码 const obj = { say(){ Array.from(arguments).forEach(item=>{ console.log(`${this.str} ${item}` ...
- iOS开发中,获取图片之后保存或下载到本地相册中
#pragma mark 先获取本地图片或者网络图片 - (void)saveHeaderImageWith:(NSString *)path { UIImage *img = [UIImage im ...
- 图像几何变换之平移(Matlab)
G=imread('aini555.jpg'); A=rgb2gray(G); se=translate(strel(),[,]); B=imdilate(A,se); figure; subplot ...
- JS 逻辑
JS 逻辑 Boolean(逻辑)对象用于将非逻辑值转换为逻辑值(true 或者 false). Boolean 对象 您可以将 Boolean 对象理解为一个产生逻辑值的对象包装器. Boolean ...
- 初级模拟电路:3-9 BJT三极管实现逻辑门
回到目录 BJT晶体管可以实现逻辑门,事实上,在场效应管被发明用于集成电路以前,各种逻辑门芯片中的电路就是用BJT晶体管来实现的.最早人们使用二极管与BJT组合来实现逻辑门,这个称为二极管-晶体管逻辑 ...
- 201871010124 王生涛《面向对象程序设计JAVA》第一周学习总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://edu.cnblogs.com/campus/xbsf/ ...
- acwing 835. Trie字符串统计
地址 https://www.acwing.com/problem/content/description/837/ 维护一个字符串集合,支持两种操作: “I x”向集合中插入一个字符串x: “Q ...
- skkyk:点分治
由题开始== 例题:求在一棵有权树上,是否存在一条路径满足权值和为K 解法:以每个点为根一次,看在他的子树间是否存在两段,其和为K;O(==) 和例题一样,对于树上问题,求某些要求的路径(数量或者存在 ...