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的内存区域简介的更多相关文章

  1. JVM的内存区域划分以及垃圾回收机制详解

    在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...

  2. JVM的内存区域划分

            JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的 ...

  3. 01 深入理解JVM的内存区域

    先来看看JVM运行时候的内存区域,如下图: 大多数 JVM 将内存区域划分为 Heap(堆).方法区.Stack(栈).本地方法栈.程序计数器.其中 Heap 和 方法区 是线程共享的,Stack.本 ...

  4. JVM的内存区域模型

    首先要明白一个概念,就是JVM的内存区域划分与java的内存区域模型是两个不同的概念,前者指的是在java中jvm会将一个程序划分为哪些块来存储对应的数据,后者是一个更宏观上的j概念,指的是java线 ...

  5. JVM的内存区域划分(转)

    原文链接:JVM的内存区域划分 JVM的内存区域划分 学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内 ...

  6. 【java】JVM的内存区域划分

    学过C语言的朋友都知道C编译器在划分内存区域的时候经常将管理的区域划分为数据段和代码段,数据段包括堆.栈以及静态数据区.那么在Java语言当中,内存又是如何划分的呢? 由于Java程序是交由JVM执行 ...

  7. 第1篇--基于jdk7和jdk8分析 JVM的内存区域

     基于jdk7和jdk8分析 JVM的内存区域 目录前言1.什么是JVM2.JRE/JDK/JVM是什么关系3.JVM执行程序的过程4. JVM的生命周期5.JVM垃圾回收一.运行时数据区的组成1.程 ...

  8. JVM(二)-内存区域之线程私有区

    概述: 对于从事C.C++开发的程序员来说,在内存管理领域,他们既是拥有最高权力的"皇帝",又是从事最基础工作的劳动人民--既拥有每个对象的"所有权", 又担负 ...

  9. 深入理解jvm之内存区域与内存溢出

    文章目录 1. Java内存区域与内存溢出异常 1.1. 运行时数据区域 1.1.1. 程序计数器 1.1.2. java虚拟机栈 1.1.3. 本地方法栈 1.1.4. Java堆(Java Hea ...

随机推荐

  1. codeforces 650D. Zip-line 线段树

    题目链接 题目的意思很简单, 就是给你n个数, m个询问, 每次询问修改某一个位置的值, 然后问你修改完之后数列的lis是多少. 询问独立. 对于原数列, 我们将它离散化, 令dp1[i]为以i为结尾 ...

  2. Asp.Net Core WebApi学习笔记(四)-- Middleware

    Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...

  3. (转)《JAVA与模式》之模板方法模式

    该文章转自:http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html 在阎宏博士的<JAVA与模式>一书中开头 ...

  4. 编程器NAND Flash 技术入门

    NAND Flash分类 SLC(Single-Level Cell)架构:单一储存单元(Cell)可储存1bit data MLC(Multi-Level Cell)架构:单一储存单元(Cell)可 ...

  5. PHP高手干货分享:要大大提高PHP效率

    1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双 引号包围的字符串中搜寻变量, 单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的”函数”(译注:PHP ...

  6. Android Animation动画(很详细)

    Android Animation   Contents: Animations Tween Animations AnimationSet Interpolator Frame-By-Frame A ...

  7. sublime编辑器怎样高速输入PHP头部版本号声明

    Sublime 菜单条->Tools→New Snippet→得到例如以下图内容: 输入下面内容: <snippet> <content><![CDATA[ < ...

  8. zoj 2966 Build The Electric System

    就是套了个prim算法就ac了 #include <stdio.h> #include <string.h> #define MaxInt 0x3f3f3f3f #define ...

  9. SQL Server和MySql获取当前数据库每个表的列数

    Sql server:(连接数据库后,点击当前数据库再新建查询) select count(c.name),o.name from syscolumns c left join sysobjects ...

  10. Tomcat启动报Error listenerStart错误

    http://xpenxpen.iteye.com/blog/1545648 今天启动Tomcat启动不了,报以下错: org.apache.catalina.core.StandardContext ...