zoukankan      html  css  js  c++  java
  • JVM(一):Java内存区域与内存溢出异常

    一.运行时数据区

      共分为5块:

    • 程序计数器      (线程私有,当前线程所执行的字节码的行号指示器)
    • Java虚拟机栈  (线程私有,证明周期与线程相同,描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,用于存储:局部变量表、操作数栈、动态链接、方法出口等信息)
    • 本地方法栈      (线程私有,本地方法栈类似于虚拟机栈,只不过执行的是Native方法)
    • Java堆         (线程共享的一块内存区域,几乎所有的对象实例以及数组都要在堆上分配)
    • 方法区              (线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据)
    • 直接内存         (并不属于JVM但是需要讲一下)

        1.1  Java虚拟机栈
        
    局部变量表: 存放了编译期可知的基本数据类型和对象引用和returnAddress类型。

      局部变量表所需的内存空间在编译期完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全正确的,在方法运行期间不会改变局部变量表的大小。

      在Java虚拟机规范中,对这个区域规定了两种异常情况:

    • 如果线程请求的栈深度大于虚拟机所允许的栈深度,将抛出StackOverflowError异常
    • 如果虚拟机可以动态扩展,扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常

     1.2  Java堆

       因为几乎所有的对象实例都要分配到堆上,而GC的主要清理目标就是对象实例,所以,Java堆是GC的主要区域。

       由于现在的收集器大都采用分代收集算法,所以Java堆还可以细分:新生代和老年代;再细致一点还可以分为Eden空间,from Survivor空间 和 to Survivor空间。

       具体 回收算法和方案  稍后 详细讲解

     

     1.3 对象的创建

    1. 检查这个new  指令的参数是否能够在常量池定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有则执行类加载。
    2. 为新生对象分配内存-指针碰撞: 堆内存是规整的,则只需要移动指针获取相应大小的空间;空闲列表:堆内存不规整,需要维护一个列表记录哪些内存空间可用,从列表中获取然后分配。会产生同步问题,CAS +失败重试机制。
    3. 内存分配完成之后,给内存空间初始化为零值(不含对象头)。
    4. 设置必要信息(属于哪个类的实例,类的元数据,对象的哈希码).
    5. 虚拟机部分对象已完成,接下来按照程序构造,初始化对象

     二. OutOfMemoryError 和  StackOverflowError

        

    1.java堆溢出  示例:

      配置参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError(dump当前内存堆的转储快照)

    public class LeetCode {
    
        // 堆溢出
        static class OOMobject {}
    
        public static void main(String[] args){
            // 堆溢出
            List<OOMobject> list = new ArrayList<>();
    
            while(true){
                list.add(new OOMobject());
            }
    
        }
    }

    使用Jhat查看解析快照文件。

      解决方案:1.查看是否是内存泄露,可以用工具查看GC Roots与对象的关联路径  判断哪些对象是无用的,什么原因导致GC无法回收

           2.如不存在泄露,应当查看 堆参数 也就是 -Xmx 和 -Xms,看一下物理内存是否还允许堆内存调大一些

           3.从代码上检查是否存在某些对象的生命周期过长、持有状态时间过长的情况,尝试优化代码减少内存消耗。 

           

    2.虚拟机栈溢出

    public class LeetCode {
    
        private int stackLength = 1;
    
        public static void main(String[] args) throws Throwable{
            LeetCode leetCode = new LeetCode();
            try{
                leetCode.stackLeak();
            } catch (Throwable e) {
                System.out.println("stack length:" + leetCode.stackLength);
                throw e;
            }
        }

      public void stackLeak() {
      stackLength++;
       stackLeak();
      }
    }

      使用 -Xss参数,减小栈的内存容量。结果抛出StackOverFlowError异常。

      

  • 相关阅读:
    标签最低高度设置minheight不兼容
    字体综合属性(font)写法顺序为
    让IE6、IE7、IE8支持CSS3的圆角、阴影样式
    微信小程序3D轮播图
    微信小程序左滑删除
    android ble 蓝牙4.0开发日志(四)
    Windows邮件服务器hMailServer,网页前端访问平台Webmail搭建
    邮件服务器hMailServer管理工具hMailServer Administrator汉化
    蓝牙设计
    Windows下搭建免费、开源的邮件服务器hMailServer
  • 原文地址:https://www.cnblogs.com/maxm/p/10966456.html
Copyright © 2011-2022 走看看