Java语言内存区域与内存溢出异常分析
小标 2018-11-26 来源 : 阅读 1379 评论 0

摘要:本文主要向大家介绍了Java语言内存区域与内存溢出异常分析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了Java语言内存区域与内存溢出异常分析,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

一、Java 虚拟机运行时数据区域:

1、方法区(Method Area)

2、虚拟机栈(VM Stack)

3、本地方法栈(Native Method Stack)

4、堆(Heap)

5、程序计数器(Program Couter Register)

 

程序计数器(Program Couter Register):较小的内存空间,它的作用可以看做是当前线程所执行的字节码指示器。每个线程都有独立的程序计数器。(线程私有)

虚拟机栈(VM Stack):Java方法执行的内存模型,每个方法被执行的时都会创建一个栈帧,存储局部变量,操作栈,动态链接,方法出口等,每个方法被调用至执行完成的过程对应一个栈帧在虚拟机栈从如栈到出栈的过程,常说的Java内存分为堆和栈(这种方法比较粗糙),这里的栈就是指虚拟机栈(线程私有,与线程生命周期相同)

本地方法栈(Native Method Stack):与虚拟机栈发挥的作用非常相似,区别在于虚拟机栈为虚拟机执行Java方法(字节码)服务。而本地方法栈是为虚拟机使用到的Native方法服务。(虚拟机)

堆(Heap):java虚拟机管理的内存中最大的一块,被所有线程共享,存放对象实例(所有线程共享)

方法区(Method Area):存储虚拟机加载的类信息,常量,静态变量(线程共享)

 

----------------------------------------------------------------------------------------------------------

直接内存(Direct Memory):并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。

在JDK中NIO引入一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它直接使用Native函数库直接分配堆外内存,然后存储在Java堆里面的DirectByteBuffer对象作为内存引用,这样能显著提高性能,避免在Java堆和Native堆中来回复制数据。

 

如何访问对象?

Object obj = new Object();

其中Object obj会存储在虚拟机栈的本地变量表中,作为一个reference类型数据出现,而new Object()存储在Java堆中。

句柄访问对象:Java堆中划出一块内存作为句柄池,reference存储对象的句柄地址。如图:

 

直接使用指针访问对象:reference中直接存储对象地址,如图:

Java虚拟机使用指针直接访问对象(第二种访问方式)。

 

二、内存溢出

Java堆溢出:对象数量达到最大堆内存容量后产生内存溢出异常

设置Java堆大小:选择run configurations——>(x)=Arguments——>VM argmuments:
-verbose:gv -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8

将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展

Java堆内存溢出异常测试代码:

/** VM Args:-Xms20m -Xms20m -XX:+HeapDumpOnOutofMemoryError */
public class HeapOOM {        static class OOMObject{            }    public static void main(String[] args) {        List<OOMObject> list = new ArrayList<OOMObject>();        while(true){            list.add(new OOMObject());        }    } }

 

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

要解决这个异常,一般通过内存影像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照分析,分析是内存泄露(GC无法回收),还是内存溢出。

 

虚拟机栈和本地方法栈溢出:-Xoss 参数(设置本地方法栈大小),-Xss 参数(设置虚拟机栈大小)

虚拟机栈和本地方法栈溢出会产生两种异常:

1、如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

2、如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

虚拟机栈和本地方法栈溢出测试代码:

/** VM Args:-Xss128k */
public class JavaVMStackSOF {        private int stackLength = 1;        public void stackLeak(){        stackLength++;        stackLeak();    }    public static void main(String[] args) {        JavaVMStackSOF oom = new JavaVMStackSOF();        try{            oom.stackLeak();        }catch(Throwable e){            e.printStackTrace();            System.out.println("stack length:" + oom.stackLength);        }            } }

运行结果:

java.lang.StackOverflowError

at aaa.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:9)

stack length:9430

 

运行时常量池溢出:由于常量池分配在方法区内,通过-XX:PermSize和-XX:MaxPermSize限制方法区大小。间接限制常量池的容量

运行时常量池溢出测试代码:

/**
* VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M */public class RuntimeConstantPoolOOM {    public static void main(String[] args) {        //使用List保持着常量池引用,避免Full GC回收常量池行为
       List<String> list = new ArrayList<String>();        //10MB的PermSize 在integer范围内足够产生OOM了
       int i = 0;        while(true){            //String.intern()这个Native方法:如果池中已经包含一个等于此String对象的            //字符串,则返回代表池中这个字符串的String对象,否则,将此String对象包含的字符串            //添加到常量池中,并且返回此String对象的引用
           list.add(String.valueOf(i++).intern());
       }

   }

}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
at java.lang.String.intern(Native Method)
at aaa.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:21)

 

方法区溢出:方法区存放Class的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等。

 

本机直接内存溢出:DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆的最大值(-Xmx指定)一样。

本机直接内存溢出测试代码:

/**
* VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M */public class DirectMemoryOOM {    
   private static final int _1MB = 1024 * 1024;    public static void main(String[] args) {
       Field unsafaField = Unsafe.class.getDeclaredFields()[0];
       unsafaField.setAccessible(true);
       Unsafe unsafe = (Unsafe)unsafaField.get(null);        while(true){
           unsafe.allocateMemory(_1MB)
       }
   }

}

运行结果:

Exception in thread "main" java.land.OutOfMemoryError

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved