专栏首页java工会Java内存区域与溢出异常

Java内存区域与溢出异常

运行时数据区

◆ ◆ ◆ ◆

Java虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间。有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户进程的启动和结束而建立销毁。具体区域如下图:

程序计数器

◆ ◆ ◆ ◆

内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成。

如果线程正在执行一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是 Native 方法,这个计数器的值则为 (Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。

Java虚拟机栈

◆ ◆ ◆ ◆

线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

局部变量表:存放了编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址)

StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。

OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。

本地方法栈

◆ ◆ ◆ ◆

区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。

有StackOverflowError 和 OutOfMemoryError 异常。

Java堆

◆ ◆ ◆ ◆

对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区。可以位于物理上不连续的空间,但是逻辑上要连续。在虚拟机启动时创建,唯一的目的就是存放对象实例。

方法区

◆ ◆ ◆ ◆

属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。会抛出OutOfMemoryError。

运行时常量池

◆ ◆ ◆ ◆

属于方法区一部分,用于存放编译期生成的各种字面量和符号引用。编译器和运行期(String 的 intern() )都可以将常量放入池中。内存有限,无法申请时抛出 OutOfMemoryError。

相对于Class文件常量池的重要特性就是具备动态性。它并不要求常量一定只能在编译器产生,也就是并不预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。

直接内存

◆ ◆ ◆ ◆

非虚拟机运行时数据区的部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁使用,会导致OutOfMemoryError

最后呈现如下图,曾经面试A厂P6时被要求当场画过:

OutOfMemoryError解决

◆ ◆ ◆ ◆

第一种:PermGen space

发生这种问题的原意是程序中使用了大量的jar或class,使java虚拟机装载类的空间不够,与Permanent Generation space有关。解决这类问题有以下两种办法:

1. 增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。如针对tomcat6.0,在catalina.sh 或catalina.bat文件中一系列环境变量名说明结束处(大约在70行左右) 增加一行:

JAVA_OPTS="-XX:PermSize=64M XX:MaxPermSize=128m"

2. 清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。

第二种:Java heap space

发生这种问题的原因是java虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了,与Heap space有关。解决这类问题有两种思路:

1. 检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改程序和算法。

2. 增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024m

第三种:unable to create new native thread

Java线程个数很多的情况下容易发生,具体解决看场景。

本文分享自微信公众号 - java工会(javagonghui),作者:小明同学

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java虚拟机-数据区域

    经常有人把java内存区分为堆内存(Heap)和栈内存(Stack),这种分发比较粗糙.

    三哥
  • JVM基础面试题及原理讲解

    对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不...

    三哥
  • 什么才算是真正的编程能力?

    三哥
  • Java虚拟机OOM之虚拟机栈和本地方法栈溢出(4)

    (1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常; (2)如果虚拟机栈可以动态扩展(当前大部分的 Java ...

    Java后端技术
  • java虚拟机-数据区域

    经常有人把java内存区分为堆内存(Heap)和栈内存(Stack),这种分发比较粗糙.

    三哥
  • Java 虚拟机管理的内存运行时数据区域解释

    Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的...

    李鹏
  • 经典面试题 | 讲一讲JVM的组成

    JVM(Java 虚拟机)算是面试必问的问题的了,而但凡问 JVM 一定会问的第一个问题就是:讲一讲 JVM 的组成?那本文就注重讲一下 JVM 的组成。

    Java团长
  • 类与对象——JVM内存分析

    木瓜煲鸡脚
  • 虚拟机如何开启SSH链接

    作为一个程序开发人员,对与服务器的了解是不必可少的,不管是web端开发还是其他开发人员。但是,对于Linux的服务器的价格比较昂贵,所以很多情况下,我们...

    卡二条的技术圈子
  • 我也想从零开始了解一下JVM虚拟机

    采用最原始的方式运行Java文件,打开任务管理器我们可以看到一个java.exe,是的,这个就是Java虚拟机,当10秒过后,main方法执行结束,java.e...

    用户7386338

扫码关注云+社区

领取腾讯云代金券