1. 概述

  对于从事c和c++程序开发的开发人员来说,在内存管理领域,他们既拥有最高权力的”皇帝“又是从事最基础工作的”劳动人民“---既拥有每个对象的”所有权“,又担负着每个对象开始到终结的维护责任。java把内存控制的权利交给了java虚拟机,一旦出现内存泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查将会是一项异常艰难的工作。

2. 运行时数据区域

  

  

  (1) 程序计数器

    程序计数器是一块较小的内存空间,他可以看作是当前线程所执行的字节码的行号指示器。由于java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器不影响,独立存储,我们称这类内存区域为”线程私有“的内存。

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

  (2) java虚拟机栈

    与程序计数器一样,java虚拟机栈也是线程私有的,每个线程创建的同时都会创建VM栈,他的生命周期与线程相同。虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧用于存储局部变量表(八种基本类型)、操作数帧、指向当前方法所属类的运行时常量池的引用、动态链接、返回结果等信息,非基本数据类型的对象在JVM栈上仅存放一个指向堆上的地址。

    当线程执行一个方法时,就会随之创建一个对应的栈帧,压入栈。方法执行完成后,就会将方法出栈。线程当前执行的方法所对应的栈帧位于VM栈的顶部。

    局部变量表存放了编译期可知的各种基本数据类型、对象引用。局部变量表所需的内存空间在编译期完全分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。

    对于这个区域规定了两种异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

  (3) 本地方法栈

    虚拟机栈为虚拟机执行java方法(即字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError异常和OutOfMemoryError异常。

  (4) java堆

    java堆是java虚拟机所管理的内存中最大的一块,存储对象实例以及数组值的区域。java堆是被所有线程共享的一块内存区域,因此在其上进行对象内存的分配均需要进行加锁。java堆是垃圾收集器管理的主要区域。java堆细分为:新生代 和老年代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由Froom Space和To Space组成。java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

  

  特点:

    a. java堆是被所有线程共享的一块内存区域,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销,是比较大的。

    b. 新生代:新建的对象都是用新生代分配内存的。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivior区,当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且还存活的对象,将被复制到老年代。

    c. 老年代:在新生代中经历了N次垃圾回收后仍然存活的对象,就会被放到老年代中。因此,可以认为老年代中存放的都是一些生命周期较长的对象。

    d. 永久代:实现方法区,主要存放所有已加载的类信息,方法信息,常量池等。永久代堆垃圾回收没有显著影响。

  (5) 方法区

·    方法区与java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、final类型的常量、静态变量、属性、方法即时编译器编译后的代码等数据。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

  (6) 运行时常量池

    运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池。当常量池无法再申请到内存时就会抛出OutOfMemoryError异常。

3. 对象的创建

  虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。之后虚拟机将为新生对象分配内存。对象所需内存的大小在来加载完成后便可以确定,为对象分配空间的任务等同于把一块确定大小的内存从java堆中划分出来。

  对象在内存存储的布局可以分为3块区域:对象头、实例数据和对齐填充。

    (1) 对象头包含两部分信息,第一部分用于存储对象自身的运行时数据,如哈希吗、GC分代年龄、锁状态标识、线程持有的锁、偏向线程ID、偏向时间戳等。对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

    (2) 对象实例是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

    (3) 对齐填充:仅仅起到占位符的作用

  对象的访问定位:java程序需要通过栈上的referrnce数据来操作堆上的具体对象。主流的访问方式有使用句柄和直接指针两种。

    (1) 使用句柄访问的话,那么java堆中将会划出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与数据类型各自的具体地址信息。

    (2) 使用直接指针访问,那么java堆对象的布局中就必须考虑如何放置访问类型的相关信息,而reference中存储的直接就是对象的地址。

  

    

    

JVM内存布局的更多相关文章

  1. JVM(二)JVM内存布局

    这几天我再次阅读了<深入理解Java虚拟机>之第二章"Java内存区域与内存溢出异常",同时也参考了一些网上的资料,现在把自己的一些认识和体会记录一下.  (本文为博主 ...

  2. JVM内存布局及GC知识回顾

    注:本文篇幅较长,且需要有一定的java基础,建议各位看官,备好瓜子.饮料.小板凳,摆个让自己舒服的姿势,慢慢细看^_^, 文中所有素材,均来自互联网,本人只是详细梳理了一遍,形成此文. 一.JVM运 ...

  3. [转帖]详解JVM内存布局及GC原理,值得收藏

    概述 https://www.toutiao.com/i6731345429574713868/ java发展历史上出现过很多垃圾回收器,各有各的适应场景,不仅仅是开发,作为运维也需要对这方面有一定的 ...

  4. JVM内存布局及GC知识

    一.JVM运行时内存布局 按java 8虚拟机规范的原始表达:(jvm)Run-Time Data Areas, 暂时翻译为"jvm运行时内存布局". 从概念上大致分为6个(逻辑) ...

  5. 深入理解Java虚拟机之JVM内存布局篇

    内存布局**** ​ JVM内存布局规定了Java在运行过程中内存申请.分配.管理的策略,保证了JVM的稳定高效运行.不同的JVM对于内存的划分方式和管理机制存在部分差异.结合JVM虚拟机规范,一起来 ...

  6. JVM 内存布局

    JVM 内存布局规定了 Java 在运行过程中内存申请.分配.管理的策略,保证了 JVM 的高效稳定运行. 线程是否共享 Heap (堆区) 堆是 OOM 故障最主要的发生区域.它是内存区域中最大的一 ...

  7. JVM内存布局(又叫Java运行时数据区)

    JVM 堆中的数据是共享的,是占用内存最大的一块区域. 可以执行字节码的模块叫作执行引擎. 执行引擎在线程切换时怎么恢复?依靠的就是程序计数器. JVM 的内存划分与多线程是息息相关的.像我们程序中运 ...

  8. JVM内存问题分析

    JVM运行时数据区: 1.方法区:类信息(类名,访问修饰符.字段描述.方法 描述等).常量.静态变量.即时编译后的class文件等.在GC时用永久代来实现方法区 2.运行时常量池:是方法区的一部分,存 ...

  9. 2万字长文包教包会 JVM 内存结构 保姆级学习笔记

    写这篇的主要原因呢,就是为了能在简历上写个"熟悉JVM底层结构",另一个原因就是能让读我文章的大家也写上这句话,真是个助人为乐的帅小伙....嗯,不单单只是面向面试学习哈,更重要的 ...

随机推荐

  1. 这些APP开发技巧可少花60万!

    用户需求——我偏不用干嘛要装? 随着手机的普及,大众流量的端口从电脑转移到手机,传统的商业平台从线下到电脑再到手机进行了转换.手机APP作为移动互联网的入口,众多创业者凭借一个手机APP成就了亿万财富 ...

  2. 【Vegas原创】MAC下,idea手动maven jar包的方法

    1,到自己的项目目录下 Vegass-MacBook-Air:gms-boyol Vegas$ pwd/Users/Vegas/SynologyDrive/Coding/workspace/gms-b ...

  3. C# 反射获取控件

    Control control = Controls.Find(]; //object o = control.GetType().GetProperty("PropertyName&quo ...

  4. 什么是面向切面编程AOP--知识点汇总

           最近在学这方面的内容,读到的这段话我感觉说的很清楚了:这种在运行时,动态地将代码切入到类的指定方法.指定位置上的编程思想就是面向切面的编程. 面向切面编程(AOP是Aspect Orie ...

  5. NPS - 数字化营销 - 净推荐值

    在获客成本高涨的时代,拥有一批超级用户,让企业更有本钱专注在提升产品及体验,创造更多的超级用户,形成良性循环.超级用户究竟要如何创造?超级用户可以定义成“忠诚用户当中最忠诚的一群人”,因此创造超级用户 ...

  6. 【转】Flask入门之上传文件到服务器

    #Sample.py # coding:utf-8 from flask import Flask,render_template,request,redirect,url_for from werk ...

  7. Canvas组件:画布,可以实现动画操作。

    Module  10 Canvas组件:画布,可以实现动画操作. TextArea:文本域. 在单行文本域中回车会激发ActionEvent. 用CheckBoxGroup实现单选框功能. Java中 ...

  8. 嵌入式开发之zynqMp ---Zynq UltraScale+ MPSoC 图像编码板zcu102

    1.1 xilinx zynqMp 架构 1.1.1 16nm 级别工艺 Zynq UltraScale+  MPSoC架构 Xilinx新一代Zynq针对控制.图像和网络应用推出了差异化的产品系,这 ...

  9. iOS 使用xib定义一个View,修改frame无效问题解决

    遇到过好多次使用自定义view,修改frame无效问题, 之前都是放弃xib,直接手写,发现手写简单的还行,复杂的UI就坑逼了.所以还是需要用到可视化编辑的xib. 整理一下,自己备忘也供iOS开发的 ...

  10. JNDI数据源的配置

    一.数据源的由来 在Java开发中,使用JDBC操作数据库的四个步骤如下:   ①加载数据库驱动程序(Class.forName("数据库驱动类");)   ②连接数据库(Conn ...