Java 8 的内存结构

VSole2022-03-10 14:37:13

java8内存结构图

虚拟机内存与本地内存的区别

Java虚拟机在执行的时候会把管理的内存分配成不同的区域,这些区域被称为虚拟机内存,同时,对于虚拟机没有直接管理的物理内存,也有一定的利用,这些被利用却不在虚拟机内存数据区的内存,我们称它为本地内存,这两种内存有一定的区别:

JVM内存

  • 受虚拟机内存大小的参数控制,当大小超过参数设置的大小时就会报OOM

本地内存

  • 本地内存不受虚拟机内存参数的限制,只受物理内存容量的限制
  • 虽然不受参数的限制,但是如果内存的占用超出物理内存的大小,同样也会报OOM

java运行时数据区域

java虚拟机在执行过程中会将所管理的内存划分为不同的区域,有的随着线程产生和消失,有的随着java进程产生和消失,根据《Java虚拟机规范》的规定,运行时数据区分为以下一个区域:

程序计数器(Program Counter Register)

程序计数器就是当前线程所执行的字节码的行号指示器,通过改变计数器的值,来选取下一行指令,通过他来实现跳转、循环、恢复线程等功能。

  • 在任何时刻,一个处理器内核只能运行一个线程,多线程是通过线程轮流切换,分配时间来完成的,这就需要有一个标志来记住每个线程执行到了哪里,这里便需要到了程序计数器。
  • 所以,程序计数器是线程私有的,每个线程都已自己的程序计数器。

虚拟机栈(JVM Stacks)

虚拟机栈是线程私有的,随线程生灭。虚拟机栈描述的是线程中的方法的内存模型:

每个方法被执行的时候,都会在虚拟机栈中同步创建一个栈帧(stack frame)。

每个栈帧的包含如下的内容

  • 局部变量表
  • 局部变量表中存储着方法里的java基本数据类型(byte/boolean/char/int/long/double/float/short)以及对象的引用(注:这里的基本数据类型指的是方法内的局部变量)
  • 操作数栈
  • 动态连接
  • 方法返回地址

方法被执行时入栈,执行完后出栈

虚拟机栈可能会抛出两种异常:

  • 如果线程请求的栈深度大于虚拟机所规定的栈深度,则会抛出StackOverFlowError即栈溢出
  • 如果虚拟机的栈容量可以动态扩展,那么当虚拟机栈申请不到内存时会抛出OutOfMemoryError即OOM内存溢出

本地方法栈(Native Method Stacks)

本地方法栈与虚拟机栈的作用是相似的,都会抛出OutOfMemoryError和StackOverFlowError,都是线程私有的,主要的区别在于:

  • 虚拟机栈执行的是java方法
  • 本地方法栈执行的是native方法(什么是Native方法?)

Java堆(Java Heap)

java堆是JVM内存中最大的一块,由所有线程共享,是由垃圾收集器管理的内存区域,主要存放对象实例,当然由于java虚拟机的发展,堆中也多了许多东西,现在主要有:

  • 对象实例
  • 类初始化生成的对象
  • 基本数据类型的数组也是对象实例
  • 字符串常量池
  • 字符串常量池原本存放于方法区,jdk7开始放置于堆中。
  • 字符串常量池存储的是string对象的直接引用,而不是直接存放的对象,是一张string table
  • 静态变量
  • 静态变量是有static修饰的变量,jdk7时从方法区迁移至堆中
  • 线程分配缓冲区(Thread Local Allocation Buffer)
  • 线程私有,但是不影响java堆的共性
  • 增加线程分配缓冲区是为了提升对象分配时的效率

java堆既可以是固定大小的,也可以是可扩展的(通过参数-Xmx和-Xms设定),如果堆无法扩展或者无法分配内存时也会报OOM。

方法区(Method Area)

方法区绝对是网上所有关于java内存结构文章争论的焦点,因为方法区的实现在java8做了一次大革新,现在我们来讨论一下:

方法区是所有线程共享的内存,在java8以前是放在JVM内存中的,由永久代实现,受JVM内存大小参数的限制,在java8中移除了永久代的内容,方法区由元空间(Meta Space)实现,并直接放到了本地内存中,不受JVM参数的限制(当然,如果物理内存被占满了,方法区也会报OOM),并且将原来放在方法区的字符串常量池和静态变量都转移到了Java堆中,方法区与其他区域不同的地方在于,方法区在编译期间和类加载完成后的内容有少许不同,不过总的来说分为这两部分:

类元信息(Klass)

  • 类元信息在类编译期间放入方法区,里面放置了类的基本信息,包括类的版本、字段、方法、接口以及常量池表(Constant Pool Table)
  • 常量池表(Constant Pool Table)存储了类在编译期间生成的字面量、符号引用(什么是字面量?什么是符号引用?),这些信息在类加载完后会被解析到运行时常量池中

运行时常量池(Runtime Constant Pool)

  • 运行时常量池主要存放在类加载后被解析的字面量与符号引用,但不止这些
  • 运行时常量池具备动态性,可以添加数据,比较多的使用就是String类的intern()方法

直接内存

直接内存位于本地内存,不属于JVM内存,但是也会在物理内存耗尽的时候报OOM,所以也讲一下。

在jdk1.4中加入了NIO(New Input/Putput)类,引入了一种基于通道(channel)与缓冲区(buffer)的新IO方式,它可以使用native函数直接分配堆外内存,然后通过存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样可以在一些场景下大大提高IO性能,避免了在java堆和native堆来回复制数据。

常见问题

什么是Native方法?

由于java是一门高级语言,离硬件底层比较远,有时候无法操作底层的资源,于是,java添加了native关键字,被native关键字修饰的方法可以用其他语言重写,这样,我们就可以写一个本地方法,然后用C语言重写,这样来操作底层资源。当然,使用了native方法会导致系统的可移植性不高,这是需要注意的。

成员变量、局部变量、类变量分别存储在内存的什么地方?

类变量

  • 类变量是用static修饰符修饰,定义在方法外的变量,随着java进程产生和销毁
  • 在java8之前把静态变量存放于方法区,在java8时存放在堆中

成员变量

  • 成员变量是定义在类中,但是没有static修饰符修饰的变量,随着类的实例产生和销毁,是类实例的一部分
  • 由于是实例的一部分,在类初始化的时候,从运行时常量池取出直接引用或者值,与初始化的对象一起放入堆中

局部变量

  • 局部变量是定义在类的方法中的变量
  • 在所在方法被调用时放入虚拟机栈的栈帧中,方法执行结束后从虚拟机栈中弹出,所以存放在虚拟机栈中

由final修饰的常量存放在哪里?

final关键字并不影响在内存中的位置,具体位置请参考上一问题。

类常量池、运行时常量池、字符串常量池有什么关系?有什么区别?

类常量池与运行时常量池都存储在方法区,而字符串常量池在jdk7时就已经从方法区迁移到了java堆中。

在类编译过程中,会把类元信息放到方法区,类元信息的其中一部分便是类常量池,主要存放字面量和符号引用,而字面量的一部分便是文本字符,在类加载时将字面量和符号引用解析为直接引用存储在运行时常量池;

对于文本字符来说,它们会在解析时查找字符串常量池,查出这个文本字符对应的字符串对象的直接引用,将直接引用存储在运行时常量池;字符串常量池存储的是字符串对象的引用,而不是字符串本身。

什么是字面量?什么是符号引用?

字面量

java代码在编译过程中是无法构建引用的,字面量就是在编译时对于数据的一种表示:

int a=1;//这个1便是字面量
String b="iloveu";//iloveu便是字面量

符号引用

由于在编译过程中并不知道每个类的地址,因为可能这个类还没有加载,所以如果你在一个类中引用了另一个类,那么你完全无法知道他的内存地址,那怎么办,我们只能用他的类名作为符号引用,在类加载完后用这个符号引用去获取他的内存地址。

例子:我在com.demo.Solution类中引用了com.test.Quest,那么我会把com.test.Quest作为符号引用存到类常量池,等类加载完后,拿着这个引用去方法区找这个类的内存地址。

虚拟机字面量
本作品采用《CC 协议》,转载必须注明作者和本文链接
Java 8 的内存结构
2022-03-10 14:37:13
java8内存结构图虚拟机内存与本地内存的区别Java虚拟机在执行的时候会把管理的内存分配成不同的区域,这些
安全芯片开放式架构实现了用户程序和操作系统的分离,降低了应用程序与安全芯片操作系统的耦合性,但同时存在国外垄断、执行效率低、内存易泄露等弊端。对于搭载了开放式运行环境的安全芯片,面向资源受限所设计的精简扩展指令集支持与行业应用高度结合,具有基于寄存器的高效指令集解释执行能力,并具有更好的指令集安全性,可支持多应用融合,有助于打破国外垄断。
无论对于Java程序员还是大数据研发人员,JVM是必须掌握的技能之一。Java提供的GC功能可以自动监测对象是否超过作用域等从而达到自动回收内存的目的,可以有效防止内存泄露,有效的使用可用内存。
清华大学新闻与传播学院新媒体研究中心将元宇宙定义为整合多种新技术而产生的新型虚实相融的互联网应用和社会形态,它基于扩展现实技术提供沉浸式体验,以及数字孪生技术生成现实世界的镜像,通过区块技术搭建经济体系,将虚拟世界与现实世界在经济系统、社交系统、身份系统上密切融合,并且允许每个用户进行内容生产和编辑。
自2008年美国国防部高级研究计划局(简称“DARPA”)正式提出建设国家网络靶场的构想开始,网络靶场技术已发展十多年。
零信任的“问题”
2022-03-24 18:32:08
“问题”是一个多义词,可以理解为负面的意义,如错误(Error)、麻烦和困难(Problem)、副作用(Side-effect),也可以理解为开放性的意义,如提问(Question)、题目和课题(Topic)。本文探讨零信任的问题,是从宏观的视角来分析:没有特别关注零信任的技术细节,重点是试图追问零信任根本的原理问题;没有具体讨论零信任的实现方法,但是却希望解构其需求框架。文章重点不在于阐明或立论
近期,一家互联网公司在北京发现其求职招聘类App的短信验证码接口遭到严重攻击,攻击次数高达1300余万次,成功匹配注册账号30余万个,给公司经济造成损失的同时也威胁了用户信息安全。
虚拟机检测技术整理
2023-05-11 09:15:35
第一次尝试恶意代码分析就遇到了虚拟机检测,于是就想着先学习一下检测的技术然后再尝试绕过。学习后最终发现,似乎最好的方法不应该是去patch所有检测方法,而是直接调试并定位检测函数再绕过。但既然已经研究了天,索性将收集到的资料整理一下,方便后人查找。恶意软件可以搜索这些文件、目录或进程的存在。VMware 虚拟机中可能会有如下的文件列表:C:\Program Files\VMware\
创建Ubuntu虚拟机首先查看可以下载使用的 Ubuntu 镜像,$?运行成功后,可以看到下面的这些镜像列表,包含各种版本的。新建一个容器,$?现在有一台 Ubuntu 18.04 版本的虚拟机在运行,对应的 IP 地址是:192.168.24.5 。如果你不想进入系统内部,也可以通过上述提到的 multipass exce 命令,来操作 Ubuntu 系统。暂停/重启虚拟机#?删除/释放虚拟机使用 delete 命令 删除虚拟机之后,该虚拟机实际上还是存在了,想要彻底删除则需要释放虚拟机
VSole
网络安全专家