当前位置: 首页 > news >正文

JVM之内存结构

1.程序计数器

定义:程序计数器(Program Counter Register)是JVM中一块较小的内存空间。解释器在解释JVM指令为机器码以供CPU执行时,会去程序计数器当中找到jvm指令的执行地址。

作用:记住下一条jvm指令的执行地址

特点:线程私有的、不会存在内存溢出

2.虚拟机栈

什么是虚拟机栈:

  • 每个线程运行时所需要的内存,称为虚拟机栈。
  • 每个Java方法执行时,Java虚拟机都会创建一个栈帧用于存储局部变量表操作数栈、动态连接、方法出口等信息。
  • 每个栈由多个栈帧组成,每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

3.本地方法栈

什么是本地方法栈:本地方法栈与虚拟机栈的作用相似,当Java虚拟机调用一些本地方法时,需要给本地方法提供的一些内存空间。本地方法是指不是由Java代码编写的一些方法,Java代码可以通过本地方法与操作系统进行交互。

4.堆

什么是堆:堆是Java虚拟机所管理的内存中最大的一块,是被所有线程共享的一块内存区域,Java世界里几乎所有的对象实例都在这里分配内存。

特点:

  • 因为堆是线程共享的,所以堆中对象都需要考虑线程安全的问题
  • 有垃圾回收机制

5.方法区

5.1 什么是方法区

        方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

        方法区是一种规范,在HotSpot虚拟机中,永久代和元空间是方法区的具体实现,在JDK7时,HotSpot已经将原本放在永久代中的字符串常量池(StringTable)、静态变量等移至Java堆中,到了JDK8,完全放弃了永久代的概念,通过在本地内存中实现的元空间来代替,并把JDK7中永久代还剩余的内容全部移到元空间。也就是说:

  • 在JDK8以前方法区的实现是永久代,永久代存在于堆内存中
  • 在JDK8及JDK8以后方法区的实现是元空间,元空间存在于本地内存中

5.2 方法区的组成

JDK1.6时的JVM内存结构

JDK1.8时的JVM内存结构

5.3 运行时常量池

1.什么是运行时常量池

运行时常量池是方法区的一部分。Class文件中除了有类的版本信息、字段、方法、接口等描述信息外,还有一项信息是常量池表,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

2.常量池和运行时常量池的区别

常量池:就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量 等信息

运行时常量池:常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量 池,并把里面的符号地址变为真实地址

5.4 StringTable

1.什么是StringTable

一般将StringTable称为串池,用来存储字符串对象,且不允许字符串对象重复,在JDK7及JDK7以前,串池存在于方法区中的运行时常量池里,在JDK8以后,串池存在于堆内存中。

2.StringTable 特性

常量池中的字符串仅是符号,第一次用到时才变为对象

利用串池的机制,来避免重复创建字符串对象

字符串变量拼接的原理是 StringBuilder (1.8)

字符串常量拼接的原理是编译期优化

可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池

  • JDK1.7及以后 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串 池中的对象返回
  • JDK1.6及以前 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份, 放入串池, 会把串池中的对象返回

注意:StringTable受垃圾回收器的管理。也就是说,StringTable中那些长时间没有被引用的字符串常量,是会被垃圾回收器回收的。

6.直接内存

6.1 直接内存概述

1.什么是直接内存

        直接内存并不是Java虚拟机内存区域中的一部分。但是这部分内存被频繁地使用,而且也可能导致OutDfMemoryError异常出现。

        在 JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆的 DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

2.作用

常见于 NIO 操作时,用于数据缓冲区

3.优缺点

分配回收成本较高、但读写性能高

6.2 直接内存的分配和回收原理

  • 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法。
  • ByteBuffer 的实现类内部,使用了 Cleaner(虚引用)来监测 ByteBuffer 对象,一旦 ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调 用 freeMemory 来释放直接内存
http://www.lryc.cn/news/106592.html

相关文章:

  • C#实现结构体与字节流的相互转化
  • 用LangChain开源框架实现知识机器人
  • HCIP——前期综合实验
  • 【2023年电赛】运动目标控制与自动追踪系统(E 题)最简单实现
  • 【IMX6ULL驱动开发学习】22.IMX6ULL开发板读取ADC(以MQ-135为例)
  • 宝塔安装ModStart,快速开启高效开发之旅!
  • 第六章 HL7 架构和可用工具 - 定义新的消息类型和结构类型
  • 通向架构师的道路之Tomcat性能调优
  • vue03 es6中对数组的操作,vue对数据监控的原理(分别对对象和数组的监控)
  • 微信小程序 - 解析富文本插件版们
  • 工厂方法模式(Factory Method)
  • js如何将图片转成BASE64编码,网页跟uniapp开发的app的区别?
  • 1400*C. Computer Game
  • windows10访问Ubuntu 18.04共享目录(已验证)
  • Linux安装redis执行make命令报错:gcc not found和*** [adlist.o] Error 1
  • R语言glmnet包详解:横截面数据建模
  • LeetCode257. 二叉树的所有路径
  • ajax、axios、fetch的区别
  • Liunx开发工具
  • Docker入门之运行Nginx案例
  • 【深度学习环境】安装anaconda、tensorflow、pycharm
  • mockery 模拟
  • 汽车后视镜反射率检测系统
  • uni-app引用外部图标库(阿里矢量图)
  • day49-Todo List(待办事项列表)
  • 寻找丢失数字:数学与位运算的解密之旅
  • 数论分块学习笔记
  • 【基础理论】了解点过程
  • 深入理解Spring MVC中的@ResponseBody注解
  • 大数据学习教程:Linux高级教程(下)