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. springcloud 通过后端去下载和预览文件,要重设跨域允许

    @RequestMapping("/download") public void downloadNet(String uri, boolean isOnLine, HttpSer ...

  2. window 启用 windows 自动登录

    启用 windows 自动登录 方案一: 1.运行命令:control userpasswords2 2.取掉复选框的钩: 方案二:(方案一无效的时候使用) 微软官网地址:https://suppor ...

  3. 搭建 pytorch框架

    Pytorch 发布了1.0,对windows的支持效果更好,因此,今天试了一下安装Pytorch.安装速度确实很快,安装也很方便. 进入pytorch的官网,选择对应的版本 根据版本输入相应命令 注 ...

  4. Linux CentOS 7下Memcached 安装与配置

    前言 本篇文章记录一下Linux CentOS 7中关于Memcached的安装与配置. 安装 安装memcached之前首先需要安装libevent,我这里用的版本是: •libevent-2.0. ...

  5. IDEA mybatis-generator 逆向工程

    1.在maven工程中的resource中创建generatorConfig.xml 2.配置generatorConfig.xml <?xml version="1.0" ...

  6. html之表单和简单CSS

    一.==表单== 1. form表单本身 <form name="myform" action="#" method="get"> ...

  7. linux下的静态库和动态库

    一.linux下的静态库   静态库中的被调用的函数的代码会在编译时一起被复制到可执行文件中去的!!可执行文件在运行不需要静态库的存在!   二.linux下动态库的构建和使用 1.动态库的构建   ...

  8. 14.链表中倒数第k个节点

    题目描述:   输入一个链表,输出该链表中倒数第k个结点. 思路分析:   设置两个指针,一个fast一个slow,都从链表头开始,让fast先走k步,然后两个指针一起走,当fast走到尾部,那么sl ...

  9. HashMap的容量大小增长原理(JDK1.6/1.7/1.8)

    . 前言 HashMap的容量大小会根据其存储数据的数量多少而自动扩充,即当HashMap存储数据的数量到达一个阈值(threshold)时,再往里面增加数据,便可能会扩充HashMap的容量. 可能 ...

  10. Django 07 Django模型基础2 (常用查询和多表关联)

    Django 07 Django模型基础2 (常用查询和多表关联) 一.常用查询 #查找数据 def search_user(request): #获取 rs = User.objects.first ...