JVM之内存区域

一、运行时数据区域

1. 程序计数器

当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,各计数器互不影响,独立存储,从而实现线程切换后能够恢复到原来的位置。如果线程执行Java方法,则计数器记录正在执行的字节码指令地址,若是native方法,则为空。

唯一一个没有任何OutOfMemoryError情况的区域

2. Java虚拟机栈

描述Java方法执行的内存模型。在每个方法执行时,都会创建一个栈帧来存储方法中的局部变量表,操作数栈,动态链接,方法出口信息等。每个方法从调用到执行完成的过程,就对应着栈帧在虚拟机栈入栈到出栈的过程。每个线程对应一个Java虚拟机栈,生命周期一致,当栈中所有栈帧都出栈时,线程也完成使命。

局部变量表

局部变量表所需的内存空间在编译期间完成分配。包括8种基本数据类型,对象引用reference类型和returnAddress类型(指向一条字节码指令的地址)

操作数栈

与局部变量表一样,操作数栈也是被组织成一个以字长为单位的数组,不过并不是像变量表一样使用索引来访问,而是通过标准的栈操作:入栈和出栈来访问的。比如方法中的语句 int a = 2;则先把操作数2入栈,然后操作数栈出栈将2赋值给方法中的a,即变量表中的int a = 2被初始化完成。

规定两种异常:

  • StackOverflowError:线程请求的栈深度大于虚拟机允许的深度
  • OutOfMemoryError:扩展时无法申请到足够的内存
3. 本地方法栈

描述Native方法执行的内存模型。与Java虚拟机栈发挥的作用相似。会抛出StackOverflowError和OutOfMemoryError两种异常

4. Java堆

Java虚拟机内存管理的内存种最大的一块,几乎所有的对象实例在这分配内存。垃圾收集器管理的主要区域,也称“GC堆”

从回收角度可分为两大类:

  • 新生代:Eden空间,From Survivor空间,To Survivior空间,通常Eden与Survivor区域大小是8:2的比例的关系
  • 老年代
堆分区的作用

为了性能的优化,提高GC的效率。如果没有分代,则当堆发生GC操作时,会对整个堆进行扫描,然后回收可回收对象,这样效率就会很慢。当分代后,我们就可以把新创建的对象放到某个地方,然后对其他区域进行回收,GC效率就会很高。

Survivor空间的作用

减少被送到老年代的对象,进而减少Full GC的发生。一般情况下,只有经历16次MinorGC还能在新生代存活的对象,才会被送到老年代。如果没有Survivor区域,即新生代不分区的话,则当Minor GC时,存活的对象就会被送到老年代。然后老年代就会很快被填满,然后触发Full GC。老年代的内存空间很大,当进行Full GC的操作消耗的时间更长,影响了程序的执行和相应速度。

Java堆允许处于不连续的物理空间中,只要逻辑连续即可。如果在堆中没有内存完成实例分配,且不可扩展时抛出OutOfMemoryError异常

5. 方法区

用于存储已被虚拟机加载的类信息,常量,静态变量等数据。除了和堆一样不需要连续的内存和可扩展,还可以不实现垃圾收集,相对而言,垃圾收集机制在这个区域出现的较少。当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常

6. 运行时常量池

方法区的一部分,类加载后,用于存放编译时期生成的各种字面量和字符引用。运行时常量池是方法区的一部分,自然当方法区无法分配足够内存时,将会抛出OutOfMemoryError异常。

二、对象的创建

在这里插入图片描述

1. 类加载检查过程

JVM遇到new指令时,首先检查指令参数是否能够在常量池中定位到一个类的符号引用:

  • 如果能够定位到,则检查这个符号引用代表的类是否被加载,解析和初始化
  • 如果不能或没有检查到,则必须执行相应的类加载过程
2. 为对象分配内存

对象所需要的内存在类加载后便可确定,故分配内存的任务等于Java堆划分一块确定大小的内存

2.1 分配方式

指针碰撞

如果Java堆内存规整:一边是用过的内存,一边是空闲的内存。指针移动所需的内存大小的距离

空闲列表

如果Java堆内存不规整:用过与空闲内存交叉,故空闲列表就是记录可用内存块,根据实例所需内存大小从列表中划分对应的空间

Java堆内存是否规整由所采用的垃圾收集器是否带有压缩整理功能决定。当使用Serial,ParNew收集器时,系统采用的分配方式是指针碰撞。当使用CMS基于标记-整理算法的收集器时,通常采用空闲列表

2.2 线程问题

并发情况下,两种分配方式都不是线程安全的。故有两种解决方法:

A. 对分配内存空间的动作进行同步处理

B.把内存分配的动作按照线程划分在不同的空间之中进行。每个线程在Java堆中预先分配本地线程分配缓冲(TLAB),那个线程需要分配内存,就在那个线程的TLAB上分配,只有用完当前的TLAB并分配新的TLAB时,才需要进行同步锁定。

3. 对象内存初始化为零值

假如使用TLAB,则在TLAB分配时进行初始化。保证了对象实例字段可不用赋初值,就可以直接使用

4. 对象进行必要的设置

主要设置对象的哈希码,GC分代年龄,类元数据信息等

5. 执行init方法

三、对象内存布局

1. 对象头

包括两个部分信息,第一部分主要用于存储对象自身运行时数据,如哈希码,GC分代年龄,线程持有的锁。第二部分为类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。

2. 实例数据

对象真正存储的有效信息,即各种类型的字段内容。包括父类继承下来的和子类中定义的字段内容。而实例数据的分配顺序受虚拟机的分配策略参数和字段在Java源码中定义顺序的影响。

分配策略:相同宽度字段分配到一起。longs/doubles、int、shorts/chars、bytes、booleans、oops。在满足这个的前提下,父类定义的变量在子类之前

3. 对齐填充

占位符作用,不是必然存在。因为HotSpot VM要求对象内存大小必须是8字节的整数倍,当对象实例数据部分没有对齐时吗,就需要对齐填充来补全。

四、对象的访问

核心:通过Java栈上的reference数据来操作堆上的具体对象

主流访问方式:使用句柄和直接指针

1. 使用句柄

当使用句柄访问时,Java堆中先划分一块内存作为句柄池,reference存储的就是对象的句柄地址,句柄地址包含了对象实例数据地址和对象类型数据。reference存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而refreence本身不需要修改。

2. 直接地址

reference存储的直接就是对象的地址,而Java堆对象布局就得考虑如何放置访问对象类型数据的地址。使用直接地址访问对象速度更快,节省了一次指针定位的时间开销(对象创建频繁),HotSpot使用该种访问方法进行对象访问

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值