JVM的内存区域划分:
  jvm的内存区域分为5部分:程序计数器,虚拟机栈,本地方法栈,堆跟方法区。
  程序计数器,虚拟机栈,本地方法栈三部分是线程私有的,堆跟方法区是公共的。
1、程序计数器
  是一块较小的内存区域,用于记录当前线程运行的位置,可以看做是程序所执行的字节码的行号指示器。如果正在执行的是一个java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是native方法,则计数器值为undefined。该部分也是jvm中唯一不会内存溢出的区域。说白了,以jvm规范的设计来讲,就是想内存溢出,也是没有机会的。
2、虚拟机栈
  就是我们通常所说的栈内存。线程中每个方法执行的时候都会创建一个栈帧,用于记录局部变量表,操作数栈,动态链接,方法出口等信息。
  在这里,如果线程请求深度大于虚拟机所允许的深度,将抛出StackOveflowError异常;如果动态扩展时无法申请到足够的内存,将抛出OutOfMemoryError异常。
  例如:无限递归调用。会导致不停的往当前线程的栈中添加栈帧,总会有栈太大,占满栈内存的时候,就会跑出StackOverflowError。
  《深入理解java虚拟机》一书中讲到,实际上jvm在这里的规定有点问题,因为当栈内存不够的时候,是因为已经使用过多还是栈空间太小,本质上是同一件事的两种描述。就是栈帧无限叠加,就会导致占用内存不断上升,从而申请内存,如果扩展到足够大,就会无法申请到足够的内存。但书中言明,经测试,单线程下无论由于栈帧太大还是虚拟机容量太小,抛出的都会stackOverflowError。但如果不限制单线程,在采用多线程情况下,只要为每个线程的栈分配的内存较大,就很容易产生OutOfMemoryError,但这跟jvm关于栈空间是否足够大的定义略有偏差。
出现StackOverflowError异常时,因为有错误堆栈信息可以阅读,相对来说较容易找到问题所在。而且使用虚拟机默认参数下,栈的深度大多数情况下达到1000-2000是很轻松的,对于正常的方法调用(包括真常递归)是足够的。但如果建立过多线程导致内存溢出,则需要考虑减少线程数量和更换64位虚拟机。若不能做到以上两者,则需要减少最大堆和减少栈容量,以换取更多的线程。
3、本地方法栈
  所发挥的作用跟虚拟机栈一样,只不过是jvm调用native方法时的栈而已。jvm规范对该部分所使用语言,使用方式以及数据结构并没有强制规定,因此不同的jvm实现是不一样的,甚至有的直接跟虚拟机栈合二为一(比如我们多数使用的HotSpot)。一样会抛出虚拟机栈的两种异常。
4、堆
  就是我们平常所说的堆内存,该部分主要用途就是存放对象实例。jvm规范中的描述是:所有的对象实例以及数组都要在堆上分配;但随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配在堆上也不是那么“绝对”了。
这也是垃圾回收的主要区域,可以通过-Xmx跟-Xms控制大小。如果堆中没有内存完成实例分配,而且也无法扩展时,抛出OutOfMemoryError.
5、方法区
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等。这里也是我们通常所说的“永久代”。但实际上并不是进入该区域的对象就真的永久存活了,这里仍然有相应的垃圾回收机制,只是相对并不频繁;而且此区域的内存回收目标主要是针对常量池的回收和对象类型的卸载。同样会有OutOfMemoryError
6、直接内存
对,除了jvm规范中定义的以上5个区域,还有一块区域是被频繁使用的。jdk1.4中加入了new Input/Output类,引入了一种基于通道与缓冲区的IO方式,就是jdk的新io中的各种reader,writer,inputstream,outputstream之类的。如果该部分内存跟虚拟机各个内存区域之和大于物理内存容量,同样会出现OutOfMemoryError。
对象的创建跟访问:
  当虚拟机遇到new指令的时候,首先将去查询这个指令的参数是否能在常量池中找到这个类的符号引用,并检查这个符号引用是否被加载、解析跟初始化过。若没有,必须先执行相应的类加载过程。
  1、类加载检查通过后,将对新生对象分配内存。对象所需的内存大小,在类加载完成后就可以完全确定。分配空间就是把一块儿确定大小的内存从java堆中划分出来。分配新内存有两种方式:“指针碰撞”跟“空闲列表”。
指针碰撞:用过的内存放一边,没用过的放一边,new的时候,指针移动一定距离,用来创建新对象。
空闲列表:用过的跟没用过的混在一起,但有一个列表记录着哪些用了哪些没用,new的时候从列表找一块儿足够大的划分给对象实例,并更新列表。
选择使用哪种方式,是由java堆是否规整决定的,而java堆是否规整是由于所采用的垃圾收集器是否带有压缩整理功能决定的。因此:Serial,ParNew等有压缩功能的垃圾收集器一般使用指针碰撞,CMS这种标记清除算法的,通常是空闲列表。
  2、并发情况下的new操作,有两种方案:
  a、对分配空间的动作进行同步处理,一半虚拟机上采用CAS配上失败重试的方式保证更新的原子性。
  b、给每个线程分配一个缓冲区,每个线程在自己缓冲区new对象,满了再进行申请。可以设置是否采用该方式,默认是true;
对象的内存布局
  HotSpot虚拟机中,对象的的内存布局分为3部分:对象头,实例数据,对齐填充。
  对象头:包括2部分,一部分用于存储对象自身的运行时数据,如HashCode,gc分带年龄,锁状态,线程持有锁,偏向锁id,偏向锁时间戳等,该部分称为“Mark Word”;另一部分是类型指针,是用来确定这个对象是哪个类的实例用的,如果对象是数组,该部分还包括数组的长度;但由于对象的访问方式有句柄跟直接指针2种,因此有的虚拟机实现种没有类型指针这部分,这类虚拟机的该部分内容在句柄中。
至于句柄跟直接指针,句柄就是引用类型的变量指针执行句柄对象(句柄对象在句柄池中),句柄对象包含到对象实例的指针跟对象类型的指针两部分;直接指针就是变量指针直接指向变量对象,但变量对象的头信息中包含一个指向对象类型信息的类型指针;很显然,我们用的HotSpot使用的是后者。

java内存区域与内存溢出的更多相关文章

  1. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  2. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  3. 深入了解Java虚拟机(1)java内存区域与内存溢出异常

    java内存区域与内存溢出异常 一.运行时数据区域 1.程序计数器:线程私有,用于存储当前所执行的指令位置 2.Java虚拟机栈:线程私有,描叙Java方法执行模型:执行方法时都会创建一个栈帧,存储局 ...

  4. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  5. 第二章Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 一.概述 对与Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每个new操作去写delete/free代码,不容易出现内存泄露和内存溢出问 题, ...

  6. 2.1 自动内存管理机制--Java内存区域与内存溢出异常

    自动内存管理机制 第二章.Java内存区域与内存溢出异常 [虚拟机中内存如何划分,以及哪部分区域.什么样代码和操作会导致内存溢出.各区域内存溢出的原因] 一.运行时数据区域 Java虚拟机所管理的内存 ...

  7. 虚拟机--第二章java内存区域与内存溢出异常--(抄书)

    这是本人阅读周志明老师的<深入理解Java虚拟机>第二版抄写的,有很多省略,不适合直接阅读,需要阅读请出门左转淘宝,右转京东,支持周老师(侵权请联系删除) 第二章java内存区域与内存溢出 ...

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

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  9. 深入理解Java虚拟机之图解Java内存区域与内存溢出异常

    Java内存区域与内存溢出异常 运行时数据区域 程序计数器 用于记录从内存执行的下一条指令的地址,线程私有的一小块内存,也是唯一不会报出OOM异常的区域 Java虚拟机栈 Java虚拟机栈(Java ...

  10. JVM内存区域与内存溢出异常

    Java虚拟机在执行java程序时会把它所管理的内存会分为若干个不同的数据区域,不同的区域在内存不足时会抛出不同的异常. >>运行时数据区域的划分 (1)程序计数器程序计数器(Progra ...

随机推荐

  1. Service Fabric 注意事项

    1. ActorTimer和ActorReminder会阻塞一个Actor的其他外部方法调用,即ActorTimer和ActorReminder内部就去未执行完毕之前,该Actor其他方法只能等待. ...

  2. VSCode配置JAVA开发环境

    VSCode配置JAVA开发环境 1:给机器安装JDK.MAVEN 下载JDK 下载路径:https://www.oracle.com/technetwork/java/javase/download ...

  3. TensorFlow创建变量

    1 使用tf.Variable函数创建变量 tf.Variable(initial_value=None,trainable=True,collections=None,validate_shape= ...

  4. datetime问题

    DateUtil.format(DateTime.now(), DatePattern.NORM_DATE_PATTERN);. 此方法将现在时间转为yy--mm--dd格式   mysql中日期运算 ...

  5. Python和FTP

    1.HTTP主要用于基于Web的文件下载以及访问Web服务,一般客户端无须登录就可以访问服务器上的文件和服务.大部分HTTP文件传输请求都用于获取网页(即将网页文件下载到本地). 2.FTP主要用于匿 ...

  6. tcp设置超时重传

    TCP超时和重传的基础是怎样根据给定连接RTT设置RTO,若TCP先于RTT开始重传,可能会在网络中引入不必要的重复数据,反之,若延迟至远大于RTT的间隔发送重传数据,整体网络利用率会随之下降.由于R ...

  7. 常用linux基础命令(持续更新...)

    删除 空目录 rmdir非空目录 rm -rf 目录名字-r 就是向下递归,不管有多少级目录,一并删除-f 就是直接强行删除,不作任何提示的意思 删除文件命令rm -f 文件名将会强行删除文件,且无提 ...

  8. [SHOI2002]百事世界杯之旅

    题目:"--在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字.只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽奖活动,获得球星背包,随声听,更克赴日韩观看世界杯. ...

  9. C++在WINdow桌面绘制文字图形

    [起因] 最近碰到一个项目,需要在电脑左面显示一些信息,因此在网上找了一些资料,成功实现在桌面绘制信息. [代码] #include "stdafx.h" #include < ...

  10. 洛谷P2071 座位安排

    题目背景 公元二零一四年四月十七日,小明参加了省赛,在一路上,他遇到了许多问题,请你帮他解决. 题目描述 已知车上有N排座位,有N*2个人参加省赛,每排座位只能坐两人,且每个人都有自己想坐的排数,问最 ...