jvm的内存区域简介
1.内存区域划分
jvm在执行java程序过程中会将管理的内存划分成若干不同的数据区域,他们分别是程序计数器,堆,方法区,虚拟机栈,本地方法栈。
1.1指令计数器
指令计数器是线程私有的,每个线程都有独立的指令计数器,计数器记录着虚拟机正在执行的字节码的指令地址,分支,循环,跳转,异常处理和线程恢复等操作都依赖这个计数器完成,如果线程执行的native方法,则这个计数器为空。
1.2虚拟机栈
虚拟机栈是线程私有的,主要用于存放局部变量表,操作栈,动态链接,方法出口等信息,由于每个方法被执行都会创建对应的线帧,方法被调用到直至完成调用的过程,实际对应线帧在操作栈中入栈和出栈的过程。在java虚拟机规范中,对这个区域规定了两种异常情况:如果线程请求的栈深度大于规定的深度,则抛出StackOverFlowError异常;如果虚拟机栈的动态扩展到了无法申请的足够内存时候将抛出OutOfMemberError异常。
1.3本地方法栈
本地方法栈和虚拟栈的功能相似,包括上述2个异常情况也一样,区别在于虚拟机栈是为虚拟机执行的java服务,而本地方法栈是为虚拟机使用的Native方法服务。
1.4堆
堆是内存中最大的区域,并且它是所有线程共享的区域。它的唯一作用就是存放对象实例,根据jvm规范的规范,它的内存空间可以使不连续的,只要在逻辑上连续的即可。
为对象分配内存就是把一块大小确定的内存从堆内存中划分出来,通常有两种方法实现:
1 、指针碰撞法
假设Java堆中内存时完整的,已分配的内存和空闲内存分别在不同的一侧,通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离。
2、空闲列表法
事实上,Java堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM通过维护一个列表,记录可用的内存块信息,当分配操作发生时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。
对象创建是一个非常频繁的行为,进行堆内存分配时还需要考虑多线程并发问题,可能出现正在给对象A分配内存,指针或记录还未更新,对象B又同时分配到原来的内存,解决这个问题有两种方案:
a、采用CAS保证数据更新操作的原子性;
b、把内存分配的行为按照线程进行划分,在不同的空间中进行,每个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)
1.5 方法区
方法区和堆一样,是被所有线程共享的运行时区域,它用于存放被虚拟机加载的累信息,常量,静态变量,即时编译后的代码等数据,跟堆的情况一样,当方法区无法满足内存分配需求时,也会抛出OutOfMemberError的异常。
运行时常量池也属于方法区的一部分。class文件除了有版本,字段,方法,接口等描述信息外,其中还有信息是常量池,用于存放编译后的各种字面量和符号引用,这部分将在类加载后存放到方法区的常量池中。另外java语言并非要求常量一定一定在编译期间产生,即是并非预置入的class文件常量池的内存才能进入方法区的运行时常量池,运行期间同样也能进入。
1.6直接内存
直接内存并不属于虚拟机运行时的数据区的一部分, 也不是java虚拟机规范中定义的内存区域,但这部分内存被频繁使用到,并且也会爆outofmemoryError异常。
在java jdk1.4中加入了NIO类,引入了基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以直接使用Native函数分配堆外的内存,然后通过存储在java堆中DirectByteBuffer对象作为这块内存的引用直接操作,这样避免了java堆和Native堆来回复制的问题,提升了行性能。
1.7对象访问方式
java虚拟机规定了一个对象变量指向一个对象的引用,并没有定义这个引用以何种方式去定位,以及访问到java堆的具体位置,所以不同的虚拟机实现对象访问的方式略有不同,大概主流的分为:句柄和直接指针。
使用句柄访问方式,java堆会划出一个内存区域作为句柄池,对象的变量存储的就是句柄池的地址,而句柄池中就存放了对象实例的数据以及对象类型信息的地址信息。若使用直接访问方式,对象变量中存储的直接是对象实例的数据以及对象类型信息的地址信息。
两种访问方式各有优势,句柄访问的优势在于对象变量可存储稳定的地址,当对象移动时,只需改变句柄池的地址,变量本身无需修改。直接访问的优势明显在于访问速度快,sun HotSpot就是采用第二种对象访问方式。
1.8 对象的内存布局
对象在内存中布局可以分成三块区域:对象头、实例数据和对齐填充。
1、对象头
对象头包括两部分信息:运行时数据和类型指针,如果对象是一个数组,还需要一块用于记录数组长度的数据。
a、运行时数据包括哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向锁ID和偏向时间戳等,这部分数据在32位和64位虚拟机中的长度分别为32bit和64bit,官方称为"Mark Word"。Mark Word被设计成非固定的数据结构,以实现在有限空间内保存尽可能多的数据。
32位的虚拟机中,对象未被锁定的状态下,Mark Word的32bit中25bit存储对象的HashCode、4bit存储对象分代年龄、2bit存储锁标志位、1bit固定为0,具体如下:
其它状态(轻量级锁定、重量级锁定、GC锁定、可偏向锁)下Mark Word的存储内容如下:
b、对象头的类型指针指向该对象的类元数据,虚拟机通过这个指针可以确定该对象是哪个类的实例。
2、实例数据
实例数据就是在程序代码中所定义的各种类型的字段,包括从父类继承的,这部分的存储顺序会受到虚拟机分配策略和字段在源码中定义顺序的影响。
3、对齐填充
由于HotSpot的自动内存管理要求对象的起始地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍,对象头的数据正好是8的整数倍,所以当实例数据不够8字节整数倍时,需要通过对齐填充进行补全。
jvm的内存区域简介的更多相关文章
- JVM的内存区域划分以及垃圾回收机制详解
在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...
- JVM的内存区域划分
JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的 ...
- 01 深入理解JVM的内存区域
先来看看JVM运行时候的内存区域,如下图: 大多数 JVM 将内存区域划分为 Heap(堆).方法区.Stack(栈).本地方法栈.程序计数器.其中 Heap 和 方法区 是线程共享的,Stack.本 ...
- JVM的内存区域模型
首先要明白一个概念,就是JVM的内存区域划分与java的内存区域模型是两个不同的概念,前者指的是在java中jvm会将一个程序划分为哪些块来存储对应的数据,后者是一个更宏观上的j概念,指的是java线 ...
- JVM的内存区域划分(转)
原文链接:JVM的内存区域划分 JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内 ...
- 【java】JVM的内存区域划分
学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行 ...
- 第1篇--基于jdk7和jdk8分析 JVM的内存区域
基于jdk7和jdk8分析 JVM的内存区域 目录前言1.什么是JVM2.JRE/JDK/JVM是什么关系3.JVM执行程序的过程4. JVM的生命周期5.JVM垃圾回收一.运行时数据区的组成1.程 ...
- JVM(二)-内存区域之线程私有区
概述: 对于从事C.C++开发的程序员来说,在内存管理领域,他们既是拥有最高权力的"皇帝",又是从事最基础工作的劳动人民--既拥有每个对象的"所有权", 又担负 ...
- 深入理解jvm之内存区域与内存溢出
文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Hea ...
随机推荐
- ue中替换行
把替换的字符替换为^p 如:123,12,3,1, 在UE力把“,”替换未“^p”,就会替换为 1231231
- HTML禁止使用右键
<html> <script type="text/javascript"> <!-- document.oncontextmenu=function ...
- [C++]Standing Ovation——Google Code Jam 2015 Qualification Round
Problem It’s opening night at the opera, and your friend is the prima donna (the lead female singer) ...
- printf不同格式表示法
格式代码 A ABC ABCDEFGH %S A ABC ABCDEFGH %5S ####A ##ABC ABCDEFGH %.5S A ABC ABCDE %5.5S ####A ##ABC AB ...
- npm使用教程(未完)
npm docs 设置镜像站 因为npmjs的官方网站,总会下载比较慢或打不开,所以通常需要设置一下镜像站来更好的安装npm库 npm install --registry http://regist ...
- [android]Gradle: 执行失败的任务 ': processDebugManifest'
发现这一问题的解决方案: gradle 组装-信息确实给了我提示清单有不同版本的 SDK 并不能合并. 编辑我的清单和 build.gradle 文件和再工作的一切所需. 要弄清楚你需要编辑 uses ...
- iPhone 5s网络钓鱼邮件,和苹果发布会同步亮相
正如预期的一样,网络犯罪分子会利用Apple最新发表的iPhone 5s消息,几乎在苹果的新产品发表会同时,这个网络钓鱼(Phishing)信件开始流传.此次,趋势科技病毒防治中心 Trend Lab ...
- 化简复杂逻辑,编写紧凑的if条件语句(二):依据if子句顺序化简条件
<化简复杂逻辑,编写紧凑的if条件语句>已经得出了跳.等.飞.异常的各自条件,方便起见这里重新贴一下. 立即跃迁:!a && b && d 等待跃迁:!a ...
- Java中static、this、super、final的用法
一. static 请先看下面这段程序: public class Hello{public static void main(String[] args){//(1)System. ...
- 拥抱开源,怎样关注Linux Kernel 邮件列表?
现在开源如此火爆.以至于张口闭口不提到都仿佛不是搞IT 的.那么怎样拥抱开源?本文适合刚開始学习的人,如有大神至此,goto exit ! 一.怎样增加开源 以Linux 为例,这么一个成功的开源项目 ...