`
raging_sweet
  • 浏览: 58854 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java内存区域与内存溢出异常

    博客分类:
  • Java
 
阅读更多

运行时数据区域:

包括 方法区虚拟机栈本地方法栈程序计数器

 

程序计数器

是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器

每一个线程都有自己私有的程序计数器。

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

 

 

JAVA虚拟机栈

也是线程私有的,生命周期和线程相同。每个方法被执行的时候都会同时创建一个栈帧(stack frame)用于存储局部变量表操作栈动态链接方法出口等信息。每个方法被调用直至执行完成的过程,就对应一个栈帧在虚拟机栈中从入栈道出栈的过程。

 

这个JAVA虚拟机栈就是我们常说的“栈”。局部变量表存放了元数据类型、引用类型

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

 

在JVM规范中,对这个区域规定了两种异常情况:

 

  1. 如果线程请求的栈深度大于JVM允许的深度,抛出StackOverflowError
  2. 如果虚拟机栈可以动态扩展(目前大部分JVM都可动态扩展),当扩展时无法申请到足够的内存时,会抛出OutOfMemoryError异常
本地方法栈
与虚拟机栈作用类似,只不过前者是执行JAVA方法服务,而本地方法栈是为Native方法服务
HotSpot将本地方法栈和虚拟机栈合二为一
和虚拟机栈一样会抛出来两种异常。

JAVA堆
JAVA堆是被所有线程共享的一块内存区域,在JVM启动时创建其作用就是存放对象实例
JVM规范规定:所有的对象实例及数组都要在堆上分配。
JAVA堆也是垃圾回收管理的主要区域。
由于现在收集器基本采用分代收集算法,所以JAVA堆还可以细分为:新生代和老年代,再细分还有Eden空间、From Survivor空间、To Survivor空间。
根据JVM规范,JAVA堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,可以是固定大小的,也可以是可扩展的(用-Xmx和-Xms控制),如果堆中没有内存,也无法扩展,抛出OutOfMemoryError


方法区
也是所有线程共享的内存区域。它用于存放虚拟机加载的类信息常量静态变量即时编译器编译后的代码等数据。
在JVM规范中被描述为堆的一部分,但却又有一个non-heap的别名。

对于HOTSPOT虚拟机,方法区又被称为永久代(Permanent Generation)
这个区域一样不需要连续的内存,可以选择固定大小或者扩展,还可以选择不实现垃圾回收。确实这个区域的数据一般不参与回收,但这些数据并不一定就是永久存在了,常量池和对类型的卸载也可以成为回收的目标。
抛出OutOfMemoryError

运行时常量池
是方法区的一部分。
编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

这个区域并不是只有编译时产生的常量,也有运行时产生的常量,比如String.intern()方法。
OutOfMemoryError异常

直接内存
Direct Memory
在JDK1.4中引入了NIO,是一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在JAVA堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。
抛OutOfMemoryError异常


Object obj = new Object();
Object obj反映到JAVA栈的本地变量表中
new Object()反映到JAVA堆中,长度不确定,在JAVA堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存放在方法区中

引用访问对象的方法主流的有两种:
  1. 使用句柄访问方式,JAVA堆中将会划分出一块内存来作为句柄池引用对象存储的是对象的句柄地址,而句柄中包含着对象实例数据类型数据各自的具体地址信息
  2. 直接指针访问方式。引用对象中直接存储的就是对象地址。,在堆中的对象又有一个指针指向方法区的对象类型数据
句柄访问方式最大的好处是在对象被移动时(垃圾回收经常会移动对象),只用改变句柄中的实例数据指针,而引用对象不用修改。
直接指针方式最大的好处是速度更快HOTSPOT使用这种方式

设置堆不可扩展,将-Xms和-Xmx参数设置一样即可

栈溢出
-Xoss参数设置本地方法栈大小(在HOTSPOT虚拟机中,由于本地方法栈和虚拟机栈是一起的,所以这个参数是无效的),-Xss参数设定栈大小。
栈溢出会抛出两种异常stackoverflow和outofmemory,前者表示线程请求的栈深度大于虚拟机所允许的最大深度,后者表示无法申请到足够的内存空间。

实验表明,单线程只会有stackoverflow,不会有outofmemory.但多线程会产生Outofmemory。

这是因为,OS分配给每个进程的内存是有限制的,比如32位windows限制为2GB,栈内存的总量是由2GB减去堆内存(Xmx),再减去方法区容量(MaxPermSize),因为程序计数器消耗内存很小,可以忽略不计。而栈内存又被多个线程所瓜分,这样在线程很多的情况下,内存就可能会耗尽。


运行时常量池溢出
通过String.intern()方法可以向运行时常量池增加内容,该方法会检测常量池中是否有某个字符串,如果有就返回池中的字符串,否则将该字符串加入常量池,再返回该常量池字符串的引用

由于常量池分配在方法区中,可以通过-XX:PermSize-XX:MaxPermSize来限制方法区大小。方法区溢出的标志就是OutOfMemoryError: PermGen Space.


方法区溢出
主要是由于动态生成了太多的类造成的,这种溢出的实际场景比如大量JSP或动态生成JSP文件的应用(JSP第一次运行时会需要编译成JAVA类)CGLIB等动态代理生成框架产生的动态类等

本机直接内存溢出
DirectMemory容量可以由-XX:MaxDirectMemorySize指定,如果不指定,则默认与JAVA堆最大值(-Xmx)一样。实际上DirectByteBuffer并没有直接申请分配内存,而是先计算,如果计算得知无足够内存可分配,就抛出异常。





分享到:
评论

相关推荐

    JAVA内存区域与内存溢出异常归类.pdf

    JAVA内存区域与内存溢出异常归类.pdf

    深入理解Java虚拟机——Java内存区域与内存溢出异常.xmind

    这是自己读《深入理解Java虚拟机》时候用XMind建立的思维导图,目的是为了能够帮助自己整理、梳理相关的知识以及方便自己日后的回顾,帮助自己建立起关于JVM的知识体系,里边也有一些对相关内容的补充,通过备注的...

    Java内存区域与内存溢出异常详解

    主要介绍了Java内存区域与内存溢出异常详解的相关资料,需要的朋友可以参考下

    lanlan2017#JavaReadingNotes#2.4.4 本机直接内存溢出1

    - 第2章 Java内存区域与内存溢出异常- 2.4 实战:OutOfMemoryError异常2.4.4 本机直接内存溢出直接内存(Direct Memory

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    第2章 Java内存区域与内存溢出异常 / 24 2.1 概述 / 24 2.2 运行时数据区域 / 25 2.2.1 程序计数器 / 25 2.2.2 Java虚拟机栈 / 26 2.2.3 本地方法栈 / 27 2.2.4 Java堆 / 27 2.2.5 方法区 / 28 2.2.6 运行...

    Java虚拟机

    第2章 Java内存区域与内存溢出异常 2.1 概述 2.2 运行时数据区域 2.2.1 程序计数器 2.2.2 Java虚拟机栈 2.2.3 本地方法栈 2.2.4 Java堆 2.2.5 方法区 2.2.6 运行时常量池 2.2.7 直接内存 2.3 HotSpot...

    学习JVM之java内存区域与异常

    关于JVM内存区域的知识对于初学者来说其实是很重要的,了解Java内存分配的原理,这对于以后JAVA的学习会有更深刻的理解。下面来看看详细介绍。

    Tomcat内存溢出的三种情况及解决办法分析

    Tomcat内存溢出的三种情况及解决办法分析 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内存原因是不一样的,当然处理方式也不一样。 这里根据平时遇到的情况和相关资料进行一个...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第4节jvm初体验-内存溢出问题的分析与解决 [免费观看] 00:17:59分钟 | 第5节jvm再体验-jvm可视化监控工具 [免费观看] 00:21:17分钟 | 第6节杂谈 [免费观看] 00:12:37分钟 | 第7节Java的发展历史00:27:24分钟 | ...

    Java开发技术大全(500个源代码).

    overflowExample.java 演示溢出 precedence.java 演示自加运算符的优先级 primeNumber.java 输出100-200之间的所有素数 ranking.java 评定成绩等级 rankingBySwitch.java 用switch语句评定成绩等级 ...

    Java常见面试问题整理.docx

    线程共享:异常:OOM 内存溢出 1.Java堆:对于大多数应用来说,Java堆是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,...

    深入理解JVM内存结构及运行原理全套视频加资料.txt

     第4讲 jvm初体验-内存溢出问题的分析与解决 免费 00:17:59  第5讲 jvm再体验-jvm可视化监控工具 免费 00:21:17  第6讲 杂谈 免费 00:12:37  第7讲 Java的发展历史 00:27:24  第8讲 Java的发展历史续 00:...

    UnderstandingTheJVM:《深入理解Java虚拟机 - Jvm高级特性与最佳实践(第三版)》阅读笔记

    本repository为《深入理解Java虚拟机 - Jvm高级特性与最佳实践(第三版)》阅读笔记,因为第一章主要讲的是Java的发展历史,这里就不做笔记,直接从第2章的"Java内存区域与内存溢出异常"讲起。 第二部分 自动内存...

    java 面试题 总结

    5、运行时异常与一般异常有何异同? 异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,...

    java8rt.jar源码-JVM:学习JVM

    第2章:java内存模型和内存溢出异常 1.运行时数据区域 1.程序计数器:线程私有 2.java虚拟机栈:线程私有,虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的时候都会创建一个栈帧,存储局部变量表、操作数...

    java堆栈的区别 -- 详解

    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,...

    超级有影响力霸气的Java面试题大全文档

    8、运行时异常与一般异常有何异同?  异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常...

    写了一首 Java 表白诗,女朋友不愁了!

    我在心里开辟了一块你的内存区域 和你的每一次美好邂逅 我都封装成记忆 深深将它压入堆栈 舍不得让它逃逸 追求你的队列很长 并发很高 我也加入了竞争 拼命挣抢着你的爱情锁 却被一直阻塞着 想念的接口没有回应 我...

    C#微软培训资料

    8.4 异常处理语句 .95 8.5 小 结 .100 第三部分 面向对象的 C#.101 第九章 面向对象的程序设计 .101 9.1 面向对象的基本概念.101 9.2 对象的模型技术 .103 9.3 面向对象的分析 .105 9.4 面向对象的设计...

    [开源]用SWT/JFace实现的放大镜软件jZoomer v1.2.0(附源码)

    Bug修正: ·解决内存溢出Bug ·解决字符串乱码Bug `解决拖拽位置不正常Bug 2. 功能添加: ·添加SystemPropertiesReader类,用于解析系统配置文件system.properties ·完成软件的国际化,...

Global site tag (gtag.js) - Google Analytics