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. C#系统登录随机验证码生成及其调用方法

    话不多说,直接上代码 public ValidateCode() { } /// <summary> /// 验证码的最大长度 /// </summary> public in ...

  2. Akka(0):聊聊对Akka的初步了解和想法

    前一段时间一直沉浸在函数式编程模式里,主要目的之一是掌握一套安全可靠的并发程序编程方法(concurrent programming),最终通过开源项目FunDA实现了单机多核CPU上程序的并行运算. ...

  3. (干货) Android实现ImageVIew多点触控及双击缩放

    支持多点触控,放大自由移动,双击可以放大缩小.直接上代码: package com.cbt.view; import android.content.Context; import android.g ...

  4. SpringCloud之Eureka集群

    前面我们介绍了SpringCloud注册中心Eureka,但是存在一个单点故障的问题,一个注册中心远远不能满足实际的生产环境,现在我们介绍一下如何搭建一个Eureka集群. 一:集群环境搭建 我们先建 ...

  5. 【Spark算子】:reduceByKey、groupByKey和combineByKey

    在spark中,reduceByKey.groupByKey和combineByKey这三种算子用的较多,结合使用过程中的体会简单总结: 我的代码实践:https://github.com/wwcom ...

  6. ThinkCMF后台验证码不显示,无法登陆怎么办?

    ThinkCMF5在本地部署之后,过一段时间可能会莫名其妙的出现后台验证码不显示的问题,不明就里.着急登陆后台的话,可以先禁用后台验证码,方法如下: 打开文件:/app/admin/controlle ...

  7. html-文件上传设置accept类型延时问题

       今天在做文件上传时,采用了jQuery的upload插件,使用过程中发现了一个很有意思也很头疼的问题. 上传按钮,第一次点击时瞬间就可以打开文件选择框,之后再点击则需要等待恐怖的8s以上. 百度 ...

  8. Liferay开发实战(1):入门

    网址: https://www.liferay.com/zh/ 文档: https://dev.liferay.com/develop 入门文章网上很多,中文的较少,存在版本太旧的问题,也缺少一步一步 ...

  9. WebRTC开发基础(WebRTC入门系列3:RTCDataChannel)

    除了视频和音频,webRTC还可以传输其他数据 例子: http://webrtc.github.io/samples/src/content/datachannel/datatransfer/ 应用 ...

  10. vue教程1-07 模板和过滤器

    vue教程1-07 模板和过滤器 一.模板 {{msg}} 数据更新模板变化 {{*msg}} 数据只绑定一次 {{{msg}}} HTML转意输出 <!DOCTYPE html> < ...