• 02-JVM内存模型:虚拟机栈与本地方法栈


    一、虚拟机栈(VM Stack)

    1.1)什么是虚拟机栈

      虚拟机栈是用于描述java方法执行的内存模型。
      每个java方法在执行时,会创建一个“栈帧(stack frame)”,栈帧的结构分为“局部变量表、操作数栈、动态链接、方法出口”几个部分(具体的作用会在字节码执行引擎章节中讲到,这里只需要了解栈帧是一个方法执行时所需要数据的结构)。我们常说的“堆内存、栈内存”中的“栈内存”指的便是虚拟机栈,确切地说,指的是虚拟机栈的栈帧中的局部变量表,因为这里存放了一个方法的所有局部变量。
      方法调用时,创建栈帧,并压入虚拟机栈;方法执行完毕,栈帧出栈并被销毁,如下图所示:

    1.2)虚拟机栈的特点

      虚拟机栈是线程隔离的,即每个线程都有自己独立的虚拟机栈。

    1.3)虚拟机栈的StackOverflowError

      若单个线程请求的栈深度大于虚拟机允许的深度,则会抛出StackOverflowError(栈溢出错误)。
      JVM会为每个线程的虚拟机栈分配一定的内存大小(-Xss参数),因此虚拟机栈能够容纳的栈帧数量是有限的,若栈帧不断进栈而不出栈,最终会导致当前线程虚拟机栈的内存空间耗尽,典型如一个无结束条件的递归函数调用,代码见下:
    复制代码
     1 /**
     2  * java栈溢出StackOverFlowError
     3  * JVM参数:-Xss128k
     4  * Created by chenjunyi on 2018/4/25.
     5  */
     6 public class JavaVMStackSOF {
     7 
     8     private int stackLength = -1;
     9 
    10     //通过递归调用造成StackOverFlowError
    11     public void stackLeak() {
    12         stackLength++;
    13         stackLeak();
    14     }
    15 
    16     public static void main(String[] args) {
    17         JavaVMStackSOF oom = new JavaVMStackSOF();
    18         try {
    19             oom.stackLeak();
    20         } catch (Throwable e) {
    21             System.out.println("Stack length:" + oom.stackLength);
    22             e.printStackTrace();
    23         }
    24     }
    25 
    26 }
    复制代码
      设置单个线程的虚拟机栈内存大小为128K,执行main方法后,抛出了StackOverflow异常
    复制代码
    1 Stack length:983
    2 java.lang.StackOverflowError
    3     at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:14)
    4     at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:15)
    5     at com.manayi.study.jvm.chapter2._02_JavaVMStackSOF.stackLeak(_02_JavaVMStackSOF.java:15)
    6     ······
    复制代码

    1.4)虚拟机栈的OutOfMemoryError

      不同于StackOverflowError,OutOfMemoryError指的是当整个虚拟机栈内存耗尽,并且无法再申请到新的内存时抛出的异常。
      JVM未提供设置整个虚拟机栈占用内存的配置参数。虚拟机栈的最大内存大致上等于“JVM进程能占用的最大内存(依赖于具体操作系统) - 最大堆内存 - 最大方法区内存 - 程序计数器内存(可以忽略不计) - JVM进程本身消耗内存”。当虚拟机栈能够使用的最大内存被耗尽后,便会抛出OutOfMemoryError,可以通过不断开启新的线程来模拟这种异常,代码如下:
    复制代码
     1 **
     2  * java栈溢出OutOfMemoryError
     3  * JVM参数:-Xss2m
     4  * Created by chenjunyi on 2018/4/25.
     5  */
     6 public class JavaVMStackOOM {
     7 
     8     private void dontStop() {
     9         while (true) {
    10         }
    11     }
    12 
    13     //通过不断的创建新的线程使Stack内存耗尽
    14     public void stackLeakByThread() {
    15         while (true) {
    16             Thread thread = new Thread(() -> dontStop());
    17             thread.start();
    18         }
    19     }
    20 
    21     public static void main(String[] args) {
    22         JavaVMStackOOM oom = new _03_JavaVMStackOOM();
    23         oom.stackLeakByThread();
    24     }
    25 
    26 }
    复制代码
      设置单个线程虚拟机栈的占用内存为2m并不断生成新的线程,最终虚拟机栈无法申请到新的内存,抛出异常:
    1 Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

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

      本地方法栈的功能和特点类似于虚拟机栈,均具有线程隔离的特点以及都能抛出StackOverflowError和OutOfMemoryError异常。
      不同的是,本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM执行的java方法。如何去服务native方法?native方法使用什么语言实现?怎么组织像栈帧这种为了服务方法的数据结构?虚拟机规范并未给出强制规定,因此不同的虚拟机实可以进行自由实现,我们常用的HotSpot虚拟机选择合并了虚拟机栈和本地方法栈。
  • 相关阅读:
    职业规划 !!
    linux上ssh配置指南
    低内存VPS用轻量级的Dropbear替换OpenSSH
    修改shell终端提示信息
    减少windows7内存占用的优化方案(内存占用才285兆 比XP还省)
    linux下提示符修改
    mysql存储过程学习笔记区块,条件,循环
    Apache下实现禁止目录浏览
    [学习指导] linux 启动过程以及 /etc/rc.d/init.d/目录的一点理解
    mysql 5.0存储过程学习总结
  • 原文地址:https://www.cnblogs.com/zhncnblogs/p/12119754.html
Copyright © 2020-2023  润新知