一 Java内存区域与HotSpot虚拟机对象
1 Java技术体系、JDK、JRE?
Java技术体系包括:
· Java程序设计语言;
· 各种硬件平台上的Java虚拟机;
· Class文件格式;
· Java API类库;
· 来自商业机构或开源社区的第三方Java类库。
JDK,即Java开发工具包,包括Java程序设计语言、Java虚拟机、Java API类库,是用于支持Java程序开发的最小环境;不仅提供了Java程序运行所需要的JRE,还提供了一系列的编译、调试工具,如javac、jconsole等。
JRE,即Java运行时环境,包括Java API类库中的Java SE API子集和Java虚拟机两部分,是用于支持Java程序运行的标准环境。
2 Java内存区域如何划分?
Java内存区域分为五部分:程序计数器、虚拟机栈、本地方法栈、方法区、堆。
(1)程序计数器:
---当前线程所执行的字节码的行号指示。若线程正在执行的是一个java方法,则计数器记录的是正在执行的虚拟机字节码指令;若线程正在执行的是一个Native方法(本地方法),则计数器值为空;
---线程私有的;
---唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
(2)虚拟机栈:
---描述的是Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存储局部变量、操作数栈、动态链接、方法出口等信息;每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
---线程私有的,生命周期与线程相同;
---使用连续的内存空间;
---两种异常:若线程请求的栈深度大于虚拟机所允许的深度,抛出StackOverflowError异常;若虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存,抛出OutOfMemoryError异常。
(3)本地方法栈:
---本地方法栈和虚拟机栈的唯一区别是虚拟机栈是为虚拟机执行java方法服务,而本地方法栈为虚拟机执行Native方法服务,其他与虚拟机栈一样。
(4)Java堆:
---虚拟机启动时创建,用于存放对象实例,几乎所有的对象实例都在Java堆中分配内存(随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术可能导致对使得实例在栈上直接分配);
---所有线程共享的;
---是垃圾收集器管理的主要区域。从内存回收角度,可分为:新生代和老年代;从内存分配的角度,Java堆中可分出多个线程私有的分配缓冲区(TLAB)。
---可以处于物理上不连续的内存空间、可以选择固定大小或者可扩展。可能抛出OutOfMemoryError异常。
(5)方法区:(HotSpot: 永久代)
---用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;
---线程共享的;
---此区域内存回收的主要目标是常量池的回收和类型的卸载;
---不需要连续内存、可以选择固定大小或者可扩展、还可以选择不进行垃圾收集。当无法满足内存分配需求时,将抛出OutOfMemoryError异常。
3 运行时常量池
---运行时常量池是方法区的一部分;
---Class文件中的常量池用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放;
---Java虚拟机规范没有对运行时常量池做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域;
---具备动态性,运行期间也可能将新的常量放入池中,如String类的intern()方法。
4 对象的创建过程
普通Java对象(不包括数组和Class对象)的创建过程为:
(1)首先检查new指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过,如果没有,则先执行相应的类加载过程。
(2)在类加载检查通过后,虚拟机将为新生对象分配内存。
分配方式有:
· “指针碰撞”:当Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器。此时,分配内存仅需要把那个指针向空闲空间那边挪动一段与对象大小相等的距离。
· “空闲列表”:当Java堆中的内存不是规整的,此时,虚拟机必须维护一个列表,记录上哪些内存块是可用的,分配的时候从列表中找到一块足够大的空间划分给对象实例,并且更新列表上的记录。
选择哪种分配方式是由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。因此,使用Serial、ParNew等带Compact过程的收集器时,系统采用的分配方式为指针碰撞;使用CMS这种基于标记-清除算法的收集器,系统采用的分配方式为空闲列表。
分配内存的操作在并发情况下并不是线程安全的,解决方法有:
· 对分配内存空间的动作进行同步处理,而实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性。
· 把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB)。
(3)虚拟机将分配到的内存空间都初始化为零值(不包括对象头)。
(4)虚拟机对对象进行必要的设置,如这个对象是哪个类的实例、对象的哈希码、对象的GC分代年龄等。
(5)一般来说,执行new指令之后还会接着执行<init>方法,把对象按照程序员的意愿进行初始化。
5 对象的内存布局
对象在内存中存储的布局可分为3块区域:对象头、实例数据、对齐填充。
对象头包括两部分:
· 存储对象自身的运行时数据(Mark Word),如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。考虑到虚拟机的空间效率,Mark Word被设计成根据对象的状态复用自己的存储空间。
· 类型指针,即对象指向它的类元数据的指针。若对象是一个Java数组,则还必须有一块用于记录数组长度的数据。
实例数据:在程序代码中所定义的各种类型的字段内容,包括父类继承下来的和子类中所定义的。存储顺序受虚拟机分配策略参数和字段在Java源码中定义顺序的影响。规则:相同宽度的字段总是被分配到一起,在父类中定义的变量会出现在子类之前。
对齐填充:起占位符的作用。对象的大小必须是8字节的整数倍。
6 对象的访问方式
(1)使用句柄访问
方式:Java堆中划分出一块内存作为句柄池,reference中存储的是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。
优点:reference中存储的是稳定的句柄地址,对象被移动时只会改变句柄中的实例数据指针,reference本身不需要修改。
(2)使用直接指针访问
方式:reference中存储的是对象地址。
优点:节省了一次指针定位的时间开销,速度更快。
- 《Effective Java》读书笔记(一)之创建和销毁对象
最近在研读<Effective Java>一书,读书不做点笔记,感觉很容易就忘掉,于是用本篇博客来记录阅读此书的笔记. 郑重声明: 由于是<Effective Java>一书的 ...
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- 《深入理解 Java 虚拟机》读书笔记:Java 内存区域与内存溢出异常
前言 最近开始看这本书,记得前段时间拿起这本书的时候,心情是相当沉重的!当时的剧本是这样的-- 内景.家里 - 下午 我(画外):唉,有点无聊啊!(偶然撇过书架)这么多书得看到什么时候啊,要不要拿一本 ...
- 深入理解Java虚拟机之读书笔记一 自动内存管理机制
一.运行时数据区域 1.程序计数器是线程的私有空间,每个线程都有.针对线程执行的是Java代码还是Native代码有两种取值,Java代码时:虚拟机字节码指令的地址:Native代码时:计数值为Und ...
- 深入理解Java虚拟机——读书笔记
首先 强烈推荐周志明老师的这本书,真的可以说是(起码中文出版界)新手了解Java虚拟机必须人手一本的教科书!!! 第二部分自动内存管理机制 由于Java虚拟机的多线程是通过线程轮流切换并分配处理器 ...
- 《深入java虚拟机》读书笔记之Java内存区域
前言 该读书笔记用于记录在学习<深入理解Java虚拟机--JVM高级特性与最佳实践>一书中的一些重要知识点,对其中的部分内容进行归纳,主要是方便之后进行复习. 运行时数据区域 Java虚拟 ...
- Java并发读书笔记:线程安全与互斥同步
目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- 读书笔记-浅析Java运行时数据区
作为一个 Java 为主语言的程序员,我偶尔也需要 用 C/C++ 写程序,在使用时让我很烦恼的一件事情就是需要对 new 出来的对象进行 delete/free 操作,我老是担心忘了这件事情,从而导 ...
随机推荐
- canvas绘图——根据鼠标位置进行缩放的实现原理
以任一点 A 缩放的基本原理: A 点为鼠标位置,正常放大是以原点放大,那么放大后 A 点就会变到 A1 点的位置 x1, y1.然后再将画布进行位移,将 A1 的位置移动到 A,则完成以 A 点缩放 ...
- python3 多线程爆破ftp、mysql、ssh
当然 也支持ip 为 127.0.0.1-255 这样的 字典放到 dict 目录里 链接: https://pan.baidu.com/s/1htchOyN5hK9nmZlWfTiFzA 密码: v ...
- Mybatis逆向工程的配置
源码github下载地址:https://github.com/wcyong/mybatisGeneratorCustom.git 参考文章:https://www.cnblogs.com/whgk/ ...
- HTTP 客户端接收数据超时
本文使用两种方式测试HTTP 客户端读数据超时的情况,一种是直接使用golang自带的http库,另一种是使用martini web框架. 1. 测试1--直接使用http库 1.1.启动server ...
- 在SAS数据步中执行过程步的简单示例
SAS中的许多过程步都是封装好的,而且SAS的编程特点决定了只能是DATA步执行完之后再执行PROC步,或者PROC步执行完之后再执行DATA步.因此有时候DATA步只能利用PROC步执行完之后的结果 ...
- win10 家庭版 升级 win10企业版
更改秘钥 我的电脑(右键)->属性-> 更改产品秘钥 -> 96YNV-9X4RP-2YYKB-RMQH4-6Q72D->重启系统 如果秘钥过期了,就百度按时间搜索,总有一个是 ...
- g2opy 记录
20190429 10:31 之前安装了g2opy,g2o也一直没好好学,跑通了slam14讲第13章的单目稠密重建.想要改写成 python版,开始仔细研究g2opy的用法.
- rediscluster安装
Redis 3.2.1集群搭建 一.概述 Redis3.0版本之后支持Cluster. 1.1.redis cluster的现状 目前redis支持的cluster特性: 1):节点自动发现 2) ...
- markdwon语法与Typora
我也是在视频中看到别人的操作,不知道这是个什么玩意? 直到无意间看到了markdown,才意识到其他人用的是markdown. 当你看到一个人使用类似 ![blockchain](https://ss ...
- linux删除文件后,空间未释放的一种情况,使用lsof查看
linux某个目录空间快满了,删除了若干的文件后,使用df -h显示还是快满的,但是df -h *显示的总的文件大小又没那么大. 某个进程正在使用删除的文件,导致删除后,空间仍然不能释放. 查看rm掉 ...