运行时错误7内存溢出_分别从运行时和GC的角度看JAVA8内存管理

运行时区域

d44e0f933c47f052ed5137b50998b9e7.png

1.程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机概念模型里(概念模型,各种虚拟机可能会通过一些更高效的方式实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令:分支、跳转、循环、异常处理、线程恢复等基础操作都会依赖这个计数器来完成。每个线程都有独立的程序计数器,用来在线程切换后能恢复到正确的执行位置,各条线程之间的计数器互不影响,独立存储。所以它是一个“线程私有”的内存区域。此内存区域是唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域。2.虚拟机栈

JVM栈是线程私有的内存区域。它描述的是java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至完成的过程,都对应着一个栈帧从入栈到出栈的过程。每当一个方法执行完成时,该栈帧就会弹出栈帧的元素作为这个方法的返回值,并且清除这个栈帧,Java栈的栈顶的栈帧就是当前正在执行的活动栈,也就是当前正在执行的方法。就像是组成动画的一帧一帧的图片,方法的调用过程也是由栈帧切换来产生结果。
很多开发人员会把Java内存分为堆内存(Heap)和栈内存(Stack),这种划分的流行只能说明大多数开发人员最关注、与对象内存分配关系最密切的内存区域是这两块,其中所指的“堆”在后面会讲到,而所指的“栈”就是JVM栈,或者说是JVM栈中的局部变量表部分。实际上Java内存区域的划分远比这要复杂。局部变量表存放了编译器可知的各种基本数据类型(int、short、byte、char、double、float、long、boolean)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一跳字节码指令的地址)。
在JVM规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,在扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

3.本地方法栈

本地方法栈和虚拟机栈所发挥的作用是很相似的,它们之间的区别不过是 虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。Sun HotSpot 直接就把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。4.Java堆

对于大多数应用来说,Java堆(Heap)是JVM所管理的内存中最大的一块。它是被所有线程共享的一块内存区域,在虚拟机启动时创建。主要用来存放对象实例,所有的对象实例以及数组都要在堆上分配。堆是垃圾收集器管理的主要区域,也被称为“GC堆”,从内存回收的角度来看,堆可以细分为:新生代和老年代;再细致一点可分为:Eden空间、From Survivor空间、To Survivor空间(空间分配比例是8:1:1)。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将抛出OutOfMemoryError异常。5.方法区

方法区(Method Area)与堆一样,也是各个线程共享的区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,也就是用来存储类的描述信息—元数据的。方法区是堆的一个逻辑部分,为了区分Java堆,它还有一个别名Non-Heap(非堆)。相对而言,GC对于这个区域的收集是很少出现的。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
在Java 7及之前版本,我们也习惯称它为“永久代”(Permanent Generation),更确切来说,应该是“HotSpot使用永久代实现了方法区”。需要注意的是,从Java 8开始,“永久代”已经被彻底移除,使用了一个元空间(Metaspace)来代替它,后面我们会详细讲解

6.运行时常量池

运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池( Constant pool table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入运行时常量池中存放。运行时常量池相对于class文件常量池的另外一个特性是具备动态性,java语言并不要求常量一定只有编译器才产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。
在近三个JDK版本(1.6、1.7、1.8)中, 运行时常量池(Runtime Constant Pool)的所处区域一直在不断的变化,在JDK1.6时它是方法区的一部分;1.7又把他放到了堆内存中;1.8之后出现了元空间,它又回到了方法区。其实,这也说明了官方对“永久代”的优化从1.7就已经开始了。7.直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是JVM规范中定义的内存区域。但这部分内存也被频繁的使用,而且也可能导致OutOfMemoryError异常出现。它在JDK中最直观的表现就是NIO,基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

从GC的角度看内存管理

73eb8be65786f9f9bd792c73d5ee8b1c.png
年轻代、老年代、方法区(老年代由元空间替换)

从Java8开始,HotSpot已经完全将永久代(Permanent Generation)移除,取而代之的是一个新的区域—元空间(MetaSpace),它使用本地内存来存储类元数据信息。也就是说,只要本地内存足够,它不会出现像永久代中“java.lang.OutOfMemoryError: PermGen space”这种错误。同样的,对永久代的设置参数 PermSize 和 MaxPermSize 也会失效。默认情况下,“元空间”的大小可以动态调整,或者使用新参数MaxMetaspaceSize 来限制本地内存分配给类元数据的大小。

为什么叫元空间?是因为这里面存储的是类的元数据信息。

元数据(Meta Date),关于数据的数据或者叫做用来描述数据的数据或者叫做信息的信息。这些定义都很是抽象,我们可以把元数据简单的理解成,最小的数据单位。元数据可以为数据说明其元素或属性(名称、大小、数据类型、等),或其结构(长度、字段、数据列),或其相关数据(位于何处、如何联系、拥有者)。

为什么要移除永久代,用元空间取代呢?

1.静态变量将会从永久代移除, 放入Java heap或者native memory. 其中建议JVM的实现中将类的元数据放入 native memory, 将字符串池类的静态变量放入Java堆中. 这样可以加载多少类的元数据就不在由MaxPermSize控制, 而由系统的实际可用空间来控制.

2.为什么这么做呢?

  • 字符串存在永久代中,容易出现性能问题和内存溢出。
  • 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
  • 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
  • 减少OOM只是表因, 更深层的原因还是要合并HotSpot和JRockit的代码, JRockit从来没有一个叫永久代的东西, 但是运行良好, 也不需要开发运维人员设置这么一个永久代的大小.

元空间特色

  • 充分利用了Java语言规范:类及相关的元数据的生命周期与类加载器的一致。
  • 每个类加载器都有它的内存区域-元空间
  • 只进行线性分配
  • 不会单独回收某个类(除了重定义类 RedefineClasses 或类加载失败)
  • 没有GC扫描或压缩
  • 元空间里的对象不会被转移
  • 如果GC发现某个类加载器不再存活,会对整个元空间进行集体回收

GC

  • Full GC时,指向元数据指针都不用再扫描,减少了Full GC的时间。
  • 很多复杂的元数据扫描的代码(尤其是CMS里面的那些)都删除了。
  • 元空间只有少量的指针指向Java堆。这包括:类的元数据中指向java.lang.Class实例的指针;数组类的元数据中,指向java.lang.Class集合的指针。
  • 没有元数据压缩的开销
  • 减少了GC Root的扫描(不再扫描虚拟机里面的已加载类的目录和其它的内部哈希表)
  • G1回收器中,并发标记阶段完成后就可以进行类的卸载

元空间内存分配模型

  • 绝大多数的类元数据的空间都从本地内存中分配
  • 用来描述类元数据的对象也被移除
  • 为元数据分配了多个映射的虚拟内存空间。
  • 为每个类加载器分配一个内存块列表。
    • 块的大小取决于类加载器的类型
    • Java反射的字节码存取器(sun.reflect.DelegatingClassLoader )占用内存更小
  • 空闲块内存返还给块内存列表
  • 当元空间为空,虚拟内存空间会被回收
  • 减少了内存碎片

异常
在JVM规范的描述中,除了程序计数器以外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError的可能。
运行时区域异常主要原因:

  • 虚拟机栈和本地方法栈 StackOverflowError、OutOfMemoryError StackOverflowError:线程请求的栈深度大于虚拟机所允许的最大深度;OutOfMemoryError:虚拟机在扩展栈时无法申请足够的内存空间 。
  • 堆 OutOfMemoryError: 对象数量到达最大堆的容量,内存泄漏、内存溢出
  • 方法区和运行时常量池 OutOfMemoryError: 反射,动态代理:CGLib、JSP、OSGI等
  • 内存泄露(Memory Leak):程序在申请内存后,对象没有被GC所回收,它始终占用内存,内存泄漏的堆积最终会造成内存溢出。
  • 内存溢出(Memory Overflow):程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。通常都是由于内存泄露导致堆栈内存不断增大,从而引发内存溢出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php baocuo error,PHP编译报错configure: error: Cannot find libmysqlclient under /usr.

今天编译PHP的时候遇到了几个错误,记录一下第一次编译的时候报错如下:configure: error: mcrypt.h not found. Please reinstall libmcrypt.报这个错是因为没有安装libmcrypt这个包,下载地址如下:wget ftp://mcrypt.hellug.gr/pub…

dart和python哪个好_RedMonk 2020 年 Q1 编程语言排行:Python 冲进前二,Dart 值得关注...

知名软件行业分析公司 RedMonk 发布了 2020 年第一季度编程语言排行榜。RedMonk 编程语言排行榜通过追踪编程语言在 GitHub 和 Stack Overflow 上的代码使用情况与讨论数量,统计分析后进行排序,其旨在深入了解潜在的语言采用趋势。该榜单一年发布两次&am…

jclouds_使用jclouds在S3上分段上传

jclouds1.目标 在上一篇文章中 ,我们研究了如何使用jclouds中的通用Blob API将内容上传到S3。 在本文中,我们将使用jclouds的S3特定的异步API上传内容并利用S3提供的分段上传功能。 2.准备 2.1。 设置自定义API 上传过程的第一部分是创建jclouds API-这…

mysql+表中公共信息,計算mysql中兩個表之間的公共行數

so heres my question...這是我的問題…Hi have two tables in mysql, called go_H and go_J, both looking like this:在mysql中有兩個表,叫做go_H和go_J,它們都是這樣的:go_Hgo_H---------------------------| gene | GoCode |-----------------------…

极域课堂管理系统软件如何取消控制_微缔电子组装业MES系统软件六大功能组成...

电子组装业MES系统软件六大功能组成MES系统软件是制造执行系统的英文简称,MES系统软件在整个企业信息集成系统中承上启下,是生产活动与管理活动信息沟通的桥梁,MES系统软件在产品从工单下发到生产成成品的整个过程中,扮演着促进生…

使用虚拟时间测试基于时间的反应堆堆芯流

Reactor Core实现了Reactive Streams规范,并处理了(可能无限的)数据流。 如果您感兴趣,请查看它提供的出色文档 。 在这里,我假设对Reactor Core库的Flux和Mono类型有一些基本的了解,并且将介绍Reactor Cor…

matlab二维数组排序函数,Matlab 用sort函数排序 二维数组

在Matlab中排序某个向量(一维)时,可以使用sort(A),其中A为待排序的向量,如果仅是用来排序A,那么直接使用sort(A)即可, 如果排序后还需要保留原来的索引可以用返回值,即[B,ind]sort(A),计算后&am…

多个cuda 被单进程沾满_报名 | 提高GPU利用率,听英伟达专家分享这个CUDA工具

随着 NVIDIA GPU 计算性能的不断提升,如何提升 GPU 利用率是开发者普遍关心的问题之一。从 Kepler 架构开始,NVIDIA GPU 支持多个 CUDA kernels 函数的并发执行,称为 Hyper-Q 技术。Hyper-Q 技术支持多个 CUDA streams、多个 CPU threads 或者…

usb转ttl模块与matlab,USB接口转TTL小板的自检测试

现在电脑基本上都不会配置DB9串行数据端口了,这给一些喜欢折腾刷机和单片机加载程序的朋友带来了诸多的不便。还好,随着技术的发展,USB接口转TTL的产品越来越成熟,而这种产品主要以采用PL-2303HX芯片作为主控器的居多,…

程序员python工作_程序员如何在工作中进步

工作,对于大部分人都是不可避免的一件事,有的人是为了生存,有的人是为了自我价值的实现,也有人是为了将来不工作而现在努力工作,出发点可能各种各样,但是工作总是大部分人不可避免的一部分。程序员&#xf…

matlab 误差椭圆,求3倍标准差误差椭圆分析的程序

根据《白话空间统计之九:方向分布(标准差椭圆)修正版》(有些地方没有理解清楚),写了下面的程序。但是好像结果不对Zmvnrnd([0.5 1.5], [0.025 0.03 ; 0.03 0.16], 50);XZ(:,1); YZ(:,2);mean_Xnanmean(X); mean_Ynanmean(Y); %椭圆圆心%确定长短半轴…

java ee cdi_Java EE CDI处理程序方法示例

java ee cdi这是CDI Disposer方法的教程。 在CDI中,由于Producer方法生成的对象随后可以注入到应用程序中,因此使用Disposer方法,以便在其工作完成时将其删除。 Disposer方法始终与Producer方法匹配。 Disposer方法使用的一个示例是当应用程…

python皮卡丘编程代码_再接再厉,用python编程13行代码解方程组(纯字符)

因为是示例为主,我们将方程组限制在二元一次方程组:x,y两个变量,两个方程。类似这样:每个方程有两个变量,x和y,形式为:axbycd由于这次有了两个方程,我们提取参数的代码就适合提炼为一…

快速提示:使用Chrome开发工具调试GWT应用程序

调试是软件开发的重要方面。 拥有正确的工具可以节省大量时间和头痛。 在GWT Super Dev模式之前,经典的Dev模式允许使用JVM调试。 开发人员可以在其IDE中设置断点,并使用调试模式来跟踪错误和错误。 现在,在超级开发模式下,情况有…

用matlab做纹理合成,关于图像纹理合成的Matlab例程

纹理是普遍存在的视觉现象,其可以描述地形、植物、矿石、纤维和皮肤等等物体的表面特征。纹理结构在图像中反映其图像像素取值的空间变化情况,这种变化具有某中统计规律,在纹理区域内的各部分具有大致相同的结构。纹理合成是利用计算机产生纹…

python 服务端与c++客户端通讯_[原创]python socket 服务端 与 c++客户端通讯,发包内容加密,支持大文件,并发...

代码经过网络搜索,综合算是原创吧.py脚本为服务端项目文件在https://github.com/jinjie412/service_client_socketimport socketserverimport jsonimport base64import osfrom te import OPMysql,Caltimeimport time#数据库操作opm OPMysql()#加密发包内容def crypt(source,ke…

matlab评估边缘检测性能,【模糊推理】模糊逻辑图像边缘检测,原理+matlab代码~...

这篇博客是接着上一篇来哒,https://blog.csdn.net/luolan9611/article/details/94285158本篇博客及上篇博客搜集的资料、实验代码、实验报告、PPT均已上传至百度网盘:链接:https://pan.baidu.com/s/1AmT4TtBAxj1FKf4KUFcsBw 提取码&#x…

qt中实现左右分割线_Qt项目中,实现屏幕截图并生成gif的详细示例(值得细读)...

总第50篇平时我们在工作和学习的过程中,有时需要将桌面的某些动作截图生成gif动图,以更生动地呈现出来。目前有很多这样的软件,并且方便易使用,比如我经常使用的GifCam,软件小巧,生成的图片文件也比较小&am…

构建Spring Boot RESTful服务+ Spring Boot执行器

总览 什么是REST? REST(代表状态转移)是Web构建的体系结构样式,已成为用于Web应用程序的标准软件设计模式 。 代表性国家转移一词最早由REST的发起人,HTTP规范的主要作者之一Roy Fielding在其博士论文中使用 。 REST上…

matlab 安装glpk,mac上安装GLPK

Obsolation note:Thanks to Dave Coleman’s comment I found out that glpk is available through homebrew now! So you just need these 2 steps to get glpk now:homebrewbrew install glpkIf you still want to read on, the old way is still here…So you want copy-pas…