前言

那些使用过 C 或者 C++ 的读者一定会发现这两门语言的内存管理机制与 Java 的不同。在使用 C 或者 C++ 编程时,程序员需要手动的去管理和维护内存,就是说需要手动的清除那些不需要的对象,否则就会出现内存泄漏与内存溢出的问题。

如果你使用 Java 语言去开发,你就会发现大多数情况下你不用去关心无用对象的回收与内存的管理,因为这一切 JVM 虚拟机已经帮我们做好了。了解 JVM 内存的各个区域将有助于我们深入了解它的管理机制,避免出现内存相关的问题和高效的解决问题。下面来讲讲面试中也是Java学习进阶中必备的JVM知识,后续还会更新完JVM系列,观看的朋友可以转发关注下!

引出问题

在 Java 编程时我们会用到许多不同类型的数据,比如临时变量、静态变量、对象、方法、类等等。 那么他们的存储方式有什么不同吗?或者说他们存在哪?

运行时数据区域

Java 虚拟机在执行 Java 程序过程中会把它所管理的内存分为若干个不同的数据区域,各自有各自的用途。

1.程序计数器

线程私有的,可以看作是当前线程所执行字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。分支、循环、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

这时唯一一个没有规定任何 OOM 异常的区域。

2.虚拟机栈

虚拟机栈也是线程私有的,生命周期与线程相同。栈里面存储的是方法的局部变量、对象的引用等等。

在这片区域中,规定了两种异常情况,当线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常。当虚拟机栈动态扩展无法申请到足够的内存时会抛出 OOM 异常。

3.本地方法栈

和虚拟机栈的作用相同,只不过它是为 Native 方法服务。HotSpot 虚拟机直接将虚拟机栈和本地方法栈合二为一了。

4.堆

堆是 Java 虚拟机所管理内存中最大的一块。是所有线程共享的一块内存区域,在虚拟机启动时创建。这个区域唯一的作用就是存放对象实例,也就是 NEW 出来的对象。这个区域也是 Java 垃圾收集器的主要作用区域。

当堆的大小再也无法扩展时,将会抛出 OOM 异常。

5.方法区

方法区也是线程共享的内存区域,用于存储已经被虚拟机加载的类信息、常量、静态变量等等。当方法区无法满足内存分配需求时,会抛出 OOM 异常。这个区域也被称为永久代。

补充

虽然上面的图里没有运行时常量池和直接内存,但是这两部分也是我们开发时经常接触的。所以给大家补充出来。

运行时常量池

运行时常量池是方法区的一部分,Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。也会抛出 OOM 异常。

直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域,但是却是NIO 操作时会直接使用的一块内存,虽然不受虚拟机参数限制,但是还是会受到本机总内存的限制,会抛出 OOM 异常。

JAVA8 的改变

对于方法区,它是线程共享的,主要用于存储类的信息,常量池,方法数据,方法代码等。我们称这个区域为永久代。

大部分程序员应该都见过 java.lang.OutOfMemoryError:PermGen space 异常,这里的 PermGen space 其实指的就是方法区。由于方法区主要存储类的相关信息,所以对于动态生成类的情况比较容易出现永久代的内存溢出,典型的场景是在 JSP 页面比较多的情况,容易出现永久代内存溢出。

在JDK 1.8中,HotSpot 虚拟机已经没有 PermGen space 这个区域了,取而代之的是一个叫做Metaspace (元空间)的东西。

变化就是移除了方法区,增加了元空间,与方法区最大的区别是:元空间不再虚拟机中,而是使用本地内存。默认情况下,元空间的大小仅受本地内存限制。

这样更改的好处:

  • 字符串常量存在方法区中,容易出现性能问题和内存溢出。
  • 类和方法的信息等比较难确定大小,因此对于方法区大小的指定比较困难,太小容易出现方法区溢出,太大容易导致堆的空间不足。
  • 方法区的垃圾回收会带来不必要的复杂度,并且回收效率偏低(垃圾回收会在下一章给大家介绍)。

内存溢出

虽然有 JVM 帮我们管理内存,但是在实际开发过程中一定还会遇到内存溢出的问题。堆,栈,方法区都有可能出现内存溢出问题。下面我们就结合几个实际的小例子来给大家展示一下,方便大家以后根据不同的情况对内存溢出问题进行快速准确的定位。

java.lang.OutOfMemoryError: Java heap space ———>java 堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数 -Xms、 -Xmx 等修改。

例子:在集合中无限加入对象,效果受到机器配置影响,可以主动更改堆大小方便演示。

java.lang.OutOfMemoryError: PermGen space ------>java永久代溢出,即方法区溢出了,一般出现于大量Class 或者 JSP 页面,或者采用 CGLIB 等反射机制的情况,因为上述情况会产生大量的 Class 信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似 -XX:PermSize=64m -XX:MaxPermSize=256m 的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出,因为常量池也是方法区的一部分。

例子:无限加载 Class,需要在 JDK 1.8 之前的版本运行,因为1.8将方法区改成了元空间,利用了机器的内存,最好手动设置 -XX:MaxPermSize,将值调小一点。

java.lang.StackOverflowError ------> 不会抛 OOM error,但也是比较常见的 Java 内存溢出。Java 虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小就会出现此种溢出。可以通过虚拟机参数 -Xss 来设置栈的大小。

例子:无法快速收敛的递归。

总结

JVM内存区域划分,便于它能够更加高效的管理自身的内存。当程序中出现这种由于JVM造成的内存溢出的情况的时候,需要根据不同的情况做不同的分析与处理。

最后

读到这的朋友可以转发关注下,后续还会更新JVM及性能调优系列的精选文章,谢谢您的支持!

delphi 算术溢出解决方法_性能优化系列:JVM 内存划分总结与内存溢出异常详解分析...相关推荐

  1. Ceph优化系列(二):Ceph主要配置参数详解

    转载:Ceph配置参数详解 概述 Ceph的配置参数很多,从网上也能搜索到一大批的调优参数,但这些参数为什么这么设置?设置为这样是否合理?解释的并不多 本文从当前我们的ceph.conf文件入手,解释 ...

  2. linux weblogic 内存溢出,weblogic10内存溢出解决方法

    在开发过程中经常会遇到weblogic内存溢出问题,用下面的办法解决了. 找到domain/bin下的setDomainEnv.cmd文件,里面可以找到以下四行代码,将值该打一倍,重启服务. set ...

  3. Fortran的堆栈溢出解决方法

    Fortran的堆栈溢出解决方法 每个线程都有自己的堆栈用来保存局部变量和函数调用信息,根据编译器不同,通常大小1~4MB之间,如果用完了就会出现stack overflow exception.此外 ...

  4. JMeter学习(十)内存溢出解决方法

    JMeter学习(十)内存溢出解决方法 参考文章: (1)JMeter学习(十)内存溢出解决方法 (2)https://www.cnblogs.com/yang-hao/p/5319720.html ...

  5. JDBC的批量查询报告内存溢出解决方法

    JDBC的批量查询报告内存溢出解决方法 参考文章: (1)JDBC的批量查询报告内存溢出解决方法 (2)https://www.cnblogs.com/DreamDrive/p/5761227.htm ...

  6. 计算机word文档无法工作,word无法打开(WORD文档打不开_解决方法_电脑基础知识_IT/计算机_专业资料)...

    word无法打开(WORD文档打不开_解决方法_电脑基础知识_IT/计算机_专业资料),哪吒游戏网给大家带来详细的word无法打开(WORD文档打不开_解决方法_电脑基础知识_IT/计算机_专业资料) ...

  7. nodejs内存溢出解决方法

    nodejs内存溢出解决方法 参考文章: (1)nodejs内存溢出解决方法 (2)https://www.cnblogs.com/qiyc/p/9634483.html 备忘一下.

  8. Java中String对象的replaceAll方法调用性能优化小技巧

    Java中String对象的replaceAll方法调用性能优化小技巧 0x01 Java中String对象的replaceAll方法调用性能优化小技巧 1.1 What? 1.2 Why? 1.3 ...

  9. 苹果id登录_英雄联盟手游用苹果id登录显示账号异常的解决方法_英雄联盟手游...

    不少小伙伴们在登录的时候,发现自己的英雄联盟手游用苹果id登录显示账号异常,这究竟是怎么回事呢,遇到此类LOL手游账号登录异常应该如何解决,这里就来和小伙伴们分享一下此次登录问题的解决方法. 情况一: ...

最新文章

  1. 神秘的 ORACLE DUAL表
  2. 洛古 P1373 小a和uim之大逃离
  3. CentOS 初体验一:VMWare 安装 CentOS
  4. linux内存和缓冲区,linux – 内存消失了(不,不是缓冲区或缓存)
  5. Ubuntu安装PHP时候出错--xml2-config not found.
  6. dataframe两个表合并_DAXSQLPython实现报表项目存在串行的财务报表合并
  7. git针对已有仓库或已有文件的初始化操作
  8. python压缩算法_LZ77压缩算法编码原理详解(结合图片和简单代码)
  9. html序列符号替换,Html标签替换(过滤掉html特殊符号)
  10. NDK编译php,Android NDK编译常见错误及解决方案
  11. .net开发中用BackgroundWorker实现多线程
  12. 【深度优先搜索】计蒜客:王子救公主
  13. 025_MapReduce样例Hadoop TopKey算法
  14. java触发器如何创建表_Java中 创建Oracle触发器的问题。
  15. shell脚本语言和java_shell脚本学习与总结
  16. pygame系列文章
  17. win7旗舰版无法安装kb2670838ie补丁都打不上去 玩h1z1
  18. 使用pano2vr生成html5全景页面
  19. viper12a电源电路图_VIPer12A功率开关电源IC.pdf
  20. 中了勒索病毒怎么办|文件解密|文件恢复

热门文章

  1. 评上了7月份的Microsoft MVP
  2. # 和 ## 的区别
  3. 全国计算机等级考试题库二级C操作题100套(第61套)
  4. rh php56 php,在全球范围内提供RHSCL PHP的最佳方法
  5. php网页多个倒计时,怎么实现一个页面有多个倒计时同时进行
  6. volatile关键字和AtomicInteger
  7. php组装json数据包,php封装json通信接口详解及实例
  8. 数据库文档生成工具V1.0
  9. 电脑知识:电脑如何连接电视,在电视上显示?
  10. 也许,这样理解HTTPS更容易