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

内存结构/运行时数据区

目录

背景知识:

内存结构

新生代如何转变成老年代

如何理解永久代、年轻代、老年代

核心概念

为什么图上看起来方法区是在堆外的?明明方法区应该 是在堆内的

NIO和BIO

1. 传统 I/O:BIO

2. 新 I/O:NIO


背景知识

JVM运行流程:

  • Java源代码编译成class字节码文件,由类加载系统装载到运行时数据区;
  • 运行时数据区把字节码加载到内存
  • 执行引擎负责将字节码翻译为底层系统指令。

纠错:是MetaSpace,不是MateSpace

内存结构

我们常说的内存结构 === 运行时数据区

运行时数据区又分为:方法区、堆、虚拟机栈、本地方法栈、程序计数器

线程私有的有:程序计数器、虚拟机栈、本地方法栈

线程共享的有:堆、方法区

程序计数器:记录当前线程正在执行的字节码指令的地址,物理上程序计数器是使用“寄存器”完成的。

虚拟机

  • 也叫线程栈,每个线程运行时所需要的内存,一个栈是由多个栈帧组成
  • 栈帧对应着每次方法调用时所占有的内存,存储的内容是:方法参数、方法内局部变量、方法返回地址
  • 一个线程每时刻只能有一个活动栈帧,对应当前正在执行的方法
  • 垃圾回收不涉及到 栈内存
  • 方法递归过多 会导致 java.lang.StackOverflowError 栈内存溢出

本地方法栈

  • 本地方法接口运行时所需要的内存空间
  • 以 native 修饰的方法就是本地方法,本地方法不是用Java写的(没有方法实现的,只有一个接口供Java调用),而是用C或C++编写,因为 Java 有些时候不能直接和操作系统底层打交道,因此Java通过接口间接调用C或C++编写的本地方法来与操作系统底层的API打交道。即Java通过本地方法调用操作系统底层功能。

  • 线程共享的区域,保存对象实例
  • 逻辑组成:年轻代(生命周期短的对象) + 老年代(生命周期长的对象)
  • JDK1.7中堆中存在 方法区的实现:永久代, JDK1.8把方法区的实现从堆移到本地内存且叫做:元空间

新生代如何转变成老年代

如何理解永久代、年轻代、老年代

一个绝佳的比喻

把JVM想象成一个 工厂

  • 年轻代 & 老年代(堆):就像是 原料仓库和生产线
    • 里面存放的是生产用的原材料生产出来的产品(对象实例)。
    • 这些原料和产品经常进进出出,不断更新(GC)。
  • 永久代:就像是 工厂的行政办公室和设计图纸库
    • 里面存放的是员工手册(字节码)、产品设计图纸(类结构)、供应商名录(常量池)。
    • 这些资料很少变动,一旦录入就会长期使用。

结论:
尽管“办公室”和“仓库”都在同一个工厂大院(堆内存)里,但它们的功能、管理方式和内容是完全不同的。这就是为什么我们说永久代在逻辑上是“非堆”(Non-Heap)。

现代变化:
到了JDK 8,这个“办公室”(永久代)被彻底搬出了工厂大院,在外面自立门户了,这就是元空间(Metaspace),它直接使用操作系统的本地内存,不再占用JVM堆的空间。

核心概念

首先需要明确:方法区是JVM规范的概念,而永久代/元空间是具体实现

  • 方法区:JVM规范定义的内存区域,用于存储类信息、常量、静态变量等
  • 永久代/元空间:方法区的具体实现方式

JDK 1.7 的永久代(PermGen)

// 在JDK 1.7中,这些数据都存储在永久代
public class Example {private static String staticVar = "静态变量";  // 存储在永久代private final String constant = "常量";        // 存储在永久代public void method() {String internStr = "字符串".intern();      // 字符串常量池在永久代}
}

永久代特点:

  • 位于堆内存
  • 有固定的大小限制(通过-XX:MaxPermSize设置)
  • 容易发生java.lang.OutOfMemoryError: PermGen space

JDK 1.8 的元空间(Metaspace)

// 在JDK 1.8中,这些数据的存储位置发生了变化
public class Example {private static String staticVar = "静态变量";  private final String constant = "常量";        public void method() {String internStr = "字符串".intern();     }
}

元空间特点:

  • 位于本地内存(系统内存),不在JVM堆中
  • 默认无大小限制(受系统内存限制)
  • 通过-XX:MaxMetaspaceSize设置上限
  • 发生OOM时错误信息:java.lang.OutOfMemoryError: Metaspace

内存结构对比

JDK 1.7 内存布局:

JVM进程内存
├── 堆内存 (Heap)
│   ├── 年轻代 (Young Generation)
│   ├── 老年代 (Old Generation)  
│   └── 永久代 (Permanent Generation) ← 方法区实现
└── 栈内存 (Stack)

JDK 1.8 内存布局:

JVM进程内存
├── 堆内存 (Heap)                    ← 只有对象实例
│   ├── 年轻代 (Young Generation)
│   └── 老年代 (Old Generation)
├── 元空间 (Metaspace)               ← 方法区实现(本地内存)
└── 栈内存 (Stack)

为什么要做这个改变?

  1. 永久代问题
    • 容易OOM,调优困难
    • FGC(FGC 就是 Full GC 的缩写,中文叫 全局垃圾回收整堆垃圾回收,FGC 是指一次性回收整个 Java 堆(包括年轻代和老年代)以及方法区/元空间(Metaspace)的垃圾)会回收永久代,但效果不好(FGC 是影响应用稳定性和响应时间的“性能杀手”。
      优化的核心目标之一就是:尽可能减少或避免 Full GC 的发生)
    • 字符串常量池在永久代中,容易内存泄漏
  1. 元空间优势
    • 自动扩展:默认不限制大小
    • 垃圾回收改进:单独的垃圾回收机制
    • 性能提升:减少Full GC触发
    • 内存管理:使用本地内存,更灵活

方法区

  • 线程共享的区域,存储的是类信息、静态变量、常量、编译后的代码、运行时常量池
  • JDK7方法区的实现叫:永久代,占用的是堆的内存空间,大小固定

为什么图上看起来方法区是在堆外的?明明方法区应该 是在堆内的

1. 永久代 (PermGen) - Java 7及以前

永久代就是在堆里面的

  • 物理位置在JVM堆内存内部划出的一块特定区域。您可以把它想象成堆里的一个“特区”。
  • 逻辑归属:因为它在堆里,所以从“JVM进程总内存”这个大逻辑上看,它属于堆。但为了和存放对象实例的“Java堆”区分开,它被称为 “非堆(Non-Heap)”
  • JDK8方法区的实现叫:元空间,占用的是本地内存的空间,大小自动调整
  1. 直接内存
  • 直接内存 不属于JVM内存管理,而是操作系统的内存
  • 常见于NIO操作时,用于数据缓冲区

NIO和BIO

1. 传统 I/O:BIO

BIO 指的是 Blocking I/O

  • 工作模式同步并阻塞
  • 通俗比喻:就像在餐厅里,一个服务员(一个线程)服务一桌客人。服务员从点餐到上菜,必须一直等待这桌客人,直到他们完全吃完。在此期间,这个服务员不能为其他桌服务,即使他大部分时间只是在“等待”。
  • 在程序中的体现:当服务器读取数据或写入数据时,如果数据没有准备好,线程会被挂起(阻塞),直到数据就绪。这会导致为每一个客户端连接都需要创建一个独立的线程,当连接数非常多时,线程数量暴涨,消耗大量系统资源,导致性能急剧下降。

2. 新 I/O:NIO

NIO 指的是 New I/O

  • 工作模式同步但非阻塞
  • 通俗比喻:就像在餐厅里,一个服务员(一个线程)服务所有客人。服务员不停地巡逻(轮询),依次询问每一桌:“需要点餐吗?”、“菜上了吗?”、“需要买单吗?”。如果某桌客人说“还没想好”,服务员就立刻去问下一桌,而不是在原地等待。
  • 在程序中的体现:NIO 的核心是 Channel(通道)Selector(选择器)
    • Channel:可以设置为非阻塞模式。当没有数据可读或可写时,线程会立即返回做别的事情,而不是被阻塞。
    • Selector:一个线程可以管理多个 Channel。Selector 会不断地轮询注册在它上面的 Channel,检查哪些 Channel 已经准备好了(如,有数据可读、可写、连接已建立)。然后,线程只去处理那些已经准备好的 Channel。
  • 分配和回收成本较高,但读写性能高,直接内存 Java代码和系统代码都能访问的到
http://www.dtcms.com/a/610590.html

相关文章:

  • ls、cd等命令均无法使用的问题解决
  • c语言编译器教学 | 深入理解C语言编译器原理与使用技巧
  • 网站开发教案深圳网站建设公司大全
  • 怎么降低网站的跳出率设置wordpress数据库用户名
  • 对基因列表中批量的基因进行GO和KEGG注释
  • 关于网站建设项目创业计划书广告软文案例
  • 代备案网站新手建站论坛
  • 宝塔FTP的进阶应用——通过cpolar内网穿透实现远程文件协同管理
  • C# 中使用 Influxdb 1.x(三)
  • 【第1章·第4节】逻辑阵列操作与应用举例
  • 百度网站下拉排名网站线上运营
  • 西宁网站制作多少钱什么是电商行业
  • 蓝光3D扫描仪在汽车模具质量控制中的应用:提升金属与注塑模具的尺寸检测效率
  • 免费自建商城网站楼盘推荐排行榜
  • VCU上下电流程学习(二)
  • 课程网站建设的目的意义做自己的网站怎么赚钱
  • Ts基础(一)—— 类型
  • ASC学习笔记0010:效果被应用时的委托
  • 深圳深圳建设网站wordpress网盘主题
  • 北京齐力众信网站建设自己怎么制作网站
  • 想找一家公司设计网站wordpress链接设置方法
  • LeetCode 424 - 替换后的最长重复字符
  • 数据结构--9:反射、枚举以及lambda表达式(了解即可)
  • Chartjs画二氧化碳浓度曲线
  • ts语法ts语法ts语法
  • 网站打开慢原因wordpress多站点 用户同步
  • 游戏被IP限制多开,如何在同一网络下用不同IP多开游戏?
  • MiniCPM-o 2.6 小参数挑战巨头 多模态直播流直达手机
  • 网站创建免费用户可信赖的手机网站设计
  • C++20--- concept 关键字 为模板参数提供了编译期可验证的约束机制