Java内存区域 

 一、java运行时数据区域

  1、 程序计数器:程序计数器占据的内存空间较小,是当前运行线程执行的字节码的计数;分支、循环、跳转、异常处理、线程恢复等都要依赖技术器来对执行的字节码进行执行位置的计算来实现的。程序计数器的内存空间是每条线程独有的,也称之为“线程私有”的内存;计数器记录的是正在运行的字节码指令的地址,而如果是Native方法(本地方法),则计数器的值为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

  2、java虚拟机栈:java虚拟机栈也是线程私有的,它的生命周期与线程相同。每个方法在运行的时候都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法的调用,就对应着一个栈帧在虚拟机栈种从入栈到出栈的过程。局部变量表中存储了编译期可知的各种基本数据类型,(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型)和returnAddress类型。java虚拟机栈会抛出StackOverflowError异常和OutOfMemoryError异常。

  3、本地方法栈:本地方法栈是本地方法的“java虚拟机栈”。

  4、Java堆:Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”;根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,当前主流的虚拟机都是按照可扩展实现的(当然可以是固定的),通过-Xmx和-Xms控制。当没有内存可以完成对象的实例的分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

  5、方法区:方法区也是被线程共享的,它存储的是:被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。

对于Java堆从内存回收的角度来看,Java堆可以分为新生代和和老年代;很多人愿意把方法区称为“永久代”(限于HotSpot虚拟机);根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

  6、运行时常量池:时方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。因为运行期间也可能会因为String类的intern()方法来将新的常量放入池中,所以当常量池无法再申请到内存时会抛出OutOfMemoryError异常。

  二、对象的创建

  1、 虚拟机遇到一条new的指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有就先进类的加载过程,在类加载完成后为新生对象分配内存。而分配内存的分配算法被受到收集器的算法的影响。在使用Serial、ParNew等带Compact过程(压缩)的收集器时,系统采用的分配算法是“指针碰撞”;而使用CMS这种基础MARK-Sweep算法(标记-清理算法)的收集器时,系统采用的分配算法是”空闲列表“;

  2、虚拟机为保证线程安全的两种内存分配机制:第一种是对分配内存空间的动作进行同步处理--实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另一种是采用本地线程分配缓冲(TLAB)。虚拟机在内存分配完成后把内存空间初始化为零值(不包括对象头),TLAB是分配的同时进行初始化。这样对象的初始值就不是空而是零,可以在不手动赋值的情况下进行调用。

  三、对象的内存布局

  1、对象在内存中存储的布局可以分为三个区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。

  2、对象头包括两部分:第一部分用于存储对象的运行时数据(如:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程的ID、偏向时间戳等);另一部分是类型指针,即指向其类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。java数组的记录长度的数据也会存在对象头中,虚拟机可以通过普通java对象的元数据信息确定java对象的大小。

  3、实例数据就是类中定义的各个字段的实例数据。

  4、对齐填充不是必然存在的,由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象示例数据部分没有对齐时,就需要通过对齐填充来补全。

  四、对象的访问定位

  1、访问对象有使用句柄和直接指针两种方式;都是通过存在Java虚拟机栈本地变量表中的reference指向Java堆来找到对象。

  2、使用句柄的方式:通过reference来访问Java堆中专门划分出来的句柄池(这时reference中存储的就是对象的句柄的地址),而句柄池中的句柄包含了到对象示例数据的指针和到对象类型数据的指针;存放对象实例对象的实例池在Java堆中,对象类型数据在方法区。这种方法的好处就是在对象移动时(垃圾收集时经常移动对象)只需要改变句柄中的指向对象实例数据的指针。

  3、使用直接指针访问,reference直接指向对象实例数据和到对象类型数据的指针。这种方式的好处就是更快,

深入理解Java虚拟机--阅读笔记一的更多相关文章

  1. 深入理解Java 虚拟机阅读笔记(一)

    1.程序计数器- 占用空间:较小 作用:字节码行号指示器 作用详情:指示指令执行,如(字节码的执行,分支,循环,跳转,异常处理,线程恢复) 特点:线程私有(每个计数器独立计算,上下文相互独立). 2. ...

  2. 深入理解Java虚拟机--阅读笔记二

    垃圾收集器与内存分配策略 一.判断对象是否已死 1.垃圾收集器在对堆进行回收前,要先判断对象是否已死.而判断的算法有引用计数算法和可达性分析算法: 2.引用计数算法是给对象添加引用计数器,有地方引用就 ...

  3. 深入理解JAVA虚拟机阅读笔记4——虚拟机类加载机制

    虚拟机把描述类的Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 在Java语言中,类型的加载.连接和初始化过程都是 ...

  4. 深入理解JAVA虚拟机阅读笔记1——JAVA内存区域

    一.Java内存区域 1.程序计数器 线程私有. 当前线程所执行的字节码的行号指示器.由于JAVA是多线程的,因此每个线程都独立的程序计数器. 异常:没有规定任何OutOfMemeryError情况的 ...

  5. 深入理解java虚拟机阅读笔记(1)运行时数据区域

    java虚拟机所管理的内存区域主要分为方法区.堆:虚拟机栈.本地方法栈.程序计数器,如图: 1.程序计数器是当前线程所执行的字节码行号指示器,用以记录当前指令执行的位置.程序计数器是线程私有的,每个线 ...

  6. 深入理解JAVA虚拟机阅读笔记6——线程安全与锁优化

    线程安全:如果一个对象可以安全的被多个线程同时使用,那它就是线程安全的. 一.Java中的线程安全 1.不可变 不可变的对象一定是线程安全的.String.枚举类型.java.lang.Number的 ...

  7. 深入理解JAVA虚拟机阅读笔记3——垃圾回收器

    一.垃圾收集器总览 新生代:Serial. ParNew. Parallel Scavenge 老年代:CMS.Serial Old. Parallel Old 最新的:G1 并行和并发的区别: 并行 ...

  8. 深入理解JAVA虚拟机阅读笔记2——垃圾回收

    线程私有的程序计数器.虚拟机栈和本地方法栈随线程而生,随线程而灭.栈中的栈帧随方法的进入和退出有条不紊的入栈和出栈. 而Java堆和方法区因为需要多大内存.创建多少对象都是不确定的,因此这两个区域是垃 ...

  9. 深入理解Java虚拟机--阅读笔记三

    垃圾收集器 手机算法是内存回收的方法论,垃圾收集器是内存回收的具体实现. 并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态 并发:值用户线程与垃圾收集线程同时执行(但并不一定是并行的) ...

随机推荐

  1. Oracle.ManagedDataAccess.Client.OracleException:“ORA-00936: 缺失表达式”

    static void Main(string[] args) { string sql = "insert into StudentC(Stuid, Stuname, Stupass) v ...

  2. 重置identity值

    如果数据库在SQL2008或以上,可以参考下面方法: DBCC CHECKIDENT ( table_name [, { NORESEED | { RESEED [, new_reseed_value ...

  3. 剑指offer编程题Java实现——面试题4后的相关题目

    题目描述: 有两个排序的数字A1和A2,内存在A1的末尾有足够多的空余空间容纳A2.请实现一个函数,把A2中的所有数字插入到A1中并且所有的数字是排序的. 还是利用从后向前比较两个数组中的数字的方式来 ...

  4. 【转】ABP使用Mysql数据库

    原文地址:https://www.cnblogs.com/LonelyCode/p/6477065.html 1.先安装Mysql的包,EntityFramework和Web项目都需要安装 2.修改W ...

  5. 对drf的初步认识

    web应用模式 1.前后端不分离 在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高. 这种应用模式比较适合纯网 ...

  6. 基于alpine用dockerfile创建的nginx镜像

    1.下载alpine镜像 [root@docker43 ~]# docker pull alpine Using default tag: latest Trying to pull reposito ...

  7. Vue2.5开发去哪儿网App 城市列表开发

     一,城市选择页面路由配置                                                                                        ...

  8. Python数据结构:栈 队列

    栈,队列的特性: 1.栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征 2.队列(queue)是一种具有 ...

  9. Python Web框架 bottle flask

    Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Python的标准库外,其不依赖任何其他模块. 1 2 3 4 pip instal ...

  10. (转) CentOS7.4 + MySQL8.0 + Git + Gogs搭建

    原文:https://blog.csdn.net/qq_16075483/article/details/80295793 1.装系统,这个不会的下面就不用看了2.CentOS7.X安装MySQL8. ...