JVM学习笔记九:对象实例化与直接内存

十分钟搞定! DeepSeek本地部署详细指南! 保姆级教程,三步搞定deepseek本地部署,不求人! 阅读详情

0. 前言

声明:
感谢尚硅谷宋红康老师的讲授。
感谢广大网友共享的笔记内容。
B站:https://www.bilibili.com/video/BV1PJ411n7xZ
本文的内容基本来源于宋老师的课件,其中有一些其他同学共享的内容,也有一些自己的理解内容。

1. 对象的实例化

对象的实例化
其中的介绍:
判断对象对应的类是否加载、链接、初始化
虚拟机遇到一条new指令,首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化(即判断类元信息是否存在)。

如果没有,那么在双亲委派模式下,使用当前类加载器以ClassLoader + 包名 + 类名为key进行查找对应的 .class文件;
- 如果没有找到文件,则抛出ClassNotFoundException异常
- 如果找到,则进行类加载,并生成对应的Class对象

为对象分配内存
首先计算对象占用空间的大小,接着在堆中划分一块内存给新对象。如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小
如果内存规整:虚拟机将采用的是**指针碰撞法(Bump The Point)**来为对象分配内存。
- 意思是所有用过的内存在一边,空闲的内存放另外一边,中间放着一个指针作为分界点的指示器,分配内存就仅仅是把指针指向空闲那边挪动一段与对象大小相等的距离罢了。如果垃圾收集器选择的是Serial ,ParNew这种基于压缩算法的,虚拟机采用这种分配方式。一般使用带Compact(整理)过程的收集器时,使用指针碰撞。

如果内存不规整:虚拟机需要维护一个空闲列表(Free List)来为对象分配内存。
- 已使用的内存和未使用的内存相互交错,那么虚拟机将采用的是空闲列表来为对象分配内存。意思是虚拟机维护了一个列表,记录上那些内存块是可用的,再分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。

选择哪种分配方式由Java堆是否规整所决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

处理并发问题

  • 采用CAS失败重试、区域加锁保证更新的原子性
  • 每个线程预先分配一块TLAB:通过设置 -XX:+UseTLAB参数来设定

初始化分配到的内存
所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用

设置对象的对象头
将对象的所属类(即类的元数据信息)、对象的 HashCode 和对象的 GC 信息、锁信息等数据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现。

执行init方法进行初始化
在Java程序的视角看来,初始化才正式开始。初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。

因此一般来说(由字节码中跟随invokespecial指令所决定),new指令之后会接着就是执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完成创建出来。

给对象属性赋值的操作

  1. 属性的默认初始化
  2. 显示初始化
  3. 代码块中的初始化
  4. 构造器中的初始化

对象实例化的过程

  1. 加载类的元信息
  2. 为对象分配内存
  3. 处理并发问题
  4. 属性的默认初始化(零值初始化)
  5. 设置对象头信息
  6. 属性的显示初始化、代码块中初始化、构造器中初始化

2. 对象的内存布局

对象的内存布局总览

  • 2.1 对象头(Header)
    对象头分为两个部分:1. 运行时元数据(Mark Word)2. 类型指针。 如果创建的是一个 Array 类型的对象,还需要在对象头中保存数组的长度信息。

运行时元数据(Mark Word)
● 哈希值(HashCode)
● GC分代年龄
● 锁状态标志
● 线程持有的锁
● 偏向线程ID
● 翩向时间戳

类型指针
指向类元数据 InstanceClass,确定该对象所属的类型。

  • 2.2 实例数据(Instance Data)
    它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括从父类继承下来的和本身拥有的字段)

  • 相同宽度的字段总是被分配在一起

  • 父类中定义的变量会出现在子类之前

  • 如果CompactFields参数为true(默认为true):子类的窄变量可能插入到父类变量的空隙

  • 2.3 对齐填充
    不是必须的,也没有特别的含义,仅仅起到占位符的作用

图例说明
对象的内存布局1
对象的内存布局2

3. 对象的访问定位

访问方式的思维导图

JVM是如何通过栈帧中的对象引用访问到其内部的对象实例呢?
对象的访问定位

3.1 句柄访问

句柄访问
优点:Reference 中存储稳定的句柄地址,当垃圾回收器工作时对象被移动(标记整理算法),这时候只需要改变句柄中的实例数据指针即可,Reference 本身不需要被修改。
缺点:需要额外的使用句柄池,占用空间。

3.2 直接指针(HotSpot采用)

直接指针
优点:直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据。
缺点:句柄访问的优点。

4. 直接内存

4.1 直接内存概述

不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存。通常,访问直接内存的速度会优于Java堆,即读写性能高。

  • 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。
  • Java的NIO库允许Java程序使用直接内存,用于数据缓冲区

4.2 非直接缓存区

使用IO读写文件,需要与磁盘交互,需要由用户态切换到内核态。在内核态时,需要两份内存存储重复数据,效率低。
非直接缓存区访问方式

4.3 直接缓存区

使用NIO时,操作系统划出的直接缓存区可以被 java 代码直接访问,只有一份。NIO适合对大文件的读写操作。
直接缓存区访问方式
也可能导致 OutOfMemoryError 异常

public class DirectMemoryOutOf {
    private static final int BUFFER = 1024 * 1024 * 20;//20MB
    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList<>();
        int count = 0;
        try {
            while(true){
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                count++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            System.out.println(count);
        }
    }
}

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory 
    at java.nio.Bits.reserveMemory(Bits.java:693)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
    at com.atguigu.java.BufferTest2.main(BufferTest2.java:20)

异常结果

由于直接内存在Java堆外,因此它的大小不会直接受限于 -Xmx 指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

  • 分配回收成本较高
  • 不受JVM内存回收管理

直接内存大小可以通过 MaxDirectMemorySize 设置。如果不指定,默认与堆的最大值 -Xmx 参数值一致。
JDK7与JDK8的变化
例子:

package com.hhyy;
import java.nio.ByteBuffer;
import java.util.Scanner;
/*
以下程序执行后,可以通过任务管理器查看Java进行的占用情况。
 */
public class TestDirectMemory {
    static int memorySize = 1024 * 1024 * 1024; // 1GB
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(memorySize);
        System.out.println("分配直接内存....");

        Scanner in = new Scanner(System.in);
        in.next();

        byteBuffer = null;
        System.out.println("直接内存被释放");


        System.gc();
        in.next();
    }

}
PreScan快速入门到精通第十一讲之PreScan道路标记,建筑物、抽象物体及交通标识 道路标记目的:路标是为了完善智能驾驶实验场景。用途:道路标记是附加在道路段上的。标记的大小{小、大}、颜色,以及相对于路段的位置和方向可以在属性编辑器中设置。也可以指定褪色和孔洞,类似于路段自动添加标记的配置。在GUI中的位置:作为一个预定义的库元素格式:NAMBOX: 汇编表中不知道。PreScan包含三个不同国家的标记:荷兰、日本和美国。可以通过在国家首选项中切换国家来隐藏或显示。附件道路标线附在路段上,并相对于路段原点定位。默认情况下,道路标记被固定在路段上,用小锚点表示。11.2 建筑物目... 阅读详情

相关推荐

运放+三极管恒流源电路设计实战:从原理到仿真一步到位(附Multisim文件)

本文详细解析了运放与三极管构建恒流源电路的核心原理,重点阐述了负反馈机制如何实现精准的电流控制。通过Multisim仿真实战,从电路搭建、参数计算到负载调整率与动态响应分析,一步步指导设计过程,并提供常见故障的调试技巧与PCB设计要点,帮助工程师从理论平稳过渡到可靠实践。

7z8x2c4v6b9的博客 711

【JVM系列】- 穿插·对象的实例化与直接内存

本此学习穿插了Java对象的内存布局,更加清楚了解到对象的创建方式以及过程,最为重要的是了解对象的布局结构,包括实例对象数据存放在堆中,类元信息在方法区,栈帧通过引用去指向对应的数据信息。对比了句柄方式和指针方式。最后学习了直接内存的内容,了解了直接内存也是会出现OOM异常。

qq_43843951的博客 1425

使用 STM32F7 和 TensorFlow Lite 开发低功耗人脸识别设备

我们讨论了 STM32F7 的特点和能力,TensorFlow Lite 在 STM32F7 上的应用,以及一些降低功耗的优化技术。- 准备模型:选择合适的人脸识别模型,在 TensorFlow 中进行训练和导出,并使用 TensorFlow Lite 转换为适用于 STM32F7 的量化模型。请注意,上述代码仅展示了如何加载和运行 TensorFlow Lite 模型的方法,实际应用中需要集成人脸检测和识别模型,并根据实际需求进行相应的输入和输出处理。结合这两个工具,我们可以开发出低功耗的人脸识别设备。

weixin_66608063的博客 2586

【jvm系列-06】深入理解对象的实例化、内存布局和访问定位

深入理解对象的实例化,内存布局和访问定位

zhenghuishengq的博客 8726

总结-NuerIPS2023-Direct Preference Optimization:Your Language Model is Secretly a Reward Model

对比PPO,DPO的泛化能力更强。

m0_60361484的博客 1606

学习海康VisionMaster之BLOB分析

6):软阈值(相对):是一种动态阈值分割方法,其核心思想是 基于图像局部特性(如背景或参考区域)自适应调整阈值范围,适用于光照变化明显、背景灰度不均的场景。3:拖入位置修正功能:这个非常重要,模版匹配成功后会得到新的匹配坐标,那和创建模版时候的原点坐标会组合成一个坐标变换矩阵,通过这个矩阵,那后续的blob分析窗口则可以实现精确定位来查找目标对象。(2):设定参数:这里阈值方式是blob的核心算法,根据不同的应用场景来选择不同的阈值方式。8:高级参数:是设定blob区域的特征范围,用于筛选出来特定的区域。

yuhouxiyang的专栏 3618

图解JVM - 8.对象实例化及直接内存

本文系统解析JVM对象实例化全过程,涵盖内存分配策略、对象头结构、访问定位机制,深入剖析直接内存原理及零拷贝优势,结合常见内存异常解决方案和20+高频面试考点,助力开发者优化内存管理、提升系统性能,并为技术面试提供深度知识储备。

Anarkh_Lee的博客 725

从零搭建宝兰德BES单机版:分离式安装、环境变量配置到控制台访问的避坑指南

本文详细介绍了从零搭建宝兰德BES单机版的完整流程,包括分离式安装、环境变量配置和控制台访问的避坑指南。针对中间件安装部署中的常见问题,提供了账号规划、JDK配置、实例创建和防火墙设置等实用解决方案,帮助开发者和运维人员高效完成BES中间件的部署工作。

weixin_32576389的博客 371

JVM-8. 对象实例化及直接内存

对象实例化及直接内存

weixin_43102784的博客 1458

PCB_Project.PrjPcb 4 Not in version control

Altium Designer中PCB项目出现"NOT in version control"错误的解决方法:1. 禁用不需要的版本控制集成(DXP→Preferences→Version Control);2. 清理项目缓存(Projects面板右键→Clean Project);3. 检查文件读写权限;4. 如无效可新建项目重新添加文件。如需使用SVN版本控制,需正确配置SVN客户端路径,创建或连接SVN仓库,并将项目文件提交至版本控制系统。注意新建SVN仓库必须使用空目录,建议使用

whm128的博客 1593

安装Office程序时无法安装的解决方案

本文主要介绍了安装Office程序时无法安装的解决方案,希望能对安装Office的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案 2.1 前置步骤 2.2 方法一 2.3 方法二

weixin_43178406的博客 15万+

JVM上篇:内存与垃圾回收篇-08-对象实例化及直接内存

不是虚拟机运行时数据区的一部分,也不是《Java 虚拟机规范》中定义的内存区域。直接内存是在 Java 堆外的、直接向系统申请的内存区间。来源于 NIO,通过存在堆中的 DirectByteBuffer 操作 Native 内存。通常,访问直接内存的速度会优于 Java 堆,即读写性能高。因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。Java 的 NIO 库允许 Java 程序使用直接内存,用于数据缓冲区。

yuanmomoya的博客 1296

一文搞定 ST22 短转储 MEMORY_NO_MORE_PAGING:看懂 SAP Paging 机制,参数 rdisp/PG_SHM 与 rdisp/PG_MAXFS 怎么设才稳

SAP系统MEMORY_NO_MORE_PAGING错误通常源于Paging资源耗尽而非物理内存不足。关键排查点包括:通过ST22确认错误类型,ST02监控Paging使用情况,检查工作进程trace中的"no more free blocks"提示。解决方案建议将rdisp/PG_SHM和rdisp/PG_MAXFS设为相同值(如250000块≈2GB),使Paging完全在内存中运行。同时需优化易耗Paging的代码逻辑,如避免滥用EXTRACT命令和超大内存对象传输。典型案例如月末

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 333

JVM:对象的实例化、直接内存

JVM:对象的实例化、直接内存

weixin_74019079的博客 517

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

<JVM上篇:内存与垃圾回收篇>08-对象实例化及直接内存

8. 对象实例化及直接内存 8.1. 对象实例化 8.1.1. 创建对象的方式 8.1.2. 创建对象的步骤 8.2. 对象内存布局 8.2.1. 对象头(Header) 8.2.2. 实例数据(Instance Data) 8.2.3. 对齐填充(Padding) 8.3. 对象的访问定位

VectorX's Blog 952

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

六,JVM之对象的实例化,直接内存和执行引擎

JVM之对象的实例化,直接内存和执行引擎 一,对像的实例化内存布局与访问定位 一,对象的实例化: 对象的创建方式: new :最常见的方式:变形:(1)Xxx的静态方法(2)XxxBuilder/XxxFactory的静态方法 Class的newInstance():反射方式,只能调用空参的构造器,权限必须是public Constructor的newInstance(xxx):反射方式,可以调用空参,带参的构造器,权限没有要求 使用clone:不调用任何构造器,当前类需要实现Clonable接口,实现c

沧海皎珠 240

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

JVM直接内存详解

磁盘上的大文件直接转到内存中以便高速读写。

fengdongnan的博客 1691

JVM工作原理与实战(二十):直接内存

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了直接内存、在直接内存上创建数据等内容。

Rye的博客 1820

对象实例化及直接内存

不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存。通常,访问直接内存的速度会优于Java堆,即读写性能高。因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。Java的NIO库允许Java程序使用直接内存,用于数据缓冲区。

qq_27352081的博客 769

【JVM Ⅲ】实例化对象&直接内存&执行引擎

对象的实例化内存布局与访问定位(new对象的过程) 实例化的几种方式: new 构造方法 单例模式的getInstance方法(静态方法) XXBuilder/XXFactory Object里面的clone(): 实现clonable()接口,重写方法==这是一个浅赋值的方法。 反序列化:将file/net → 带有对象信息的二进制流 反射: 构造方法Constructor的newInstance(); 类Class的新建实例对象的方法已经被淘汰了。 创建对象的步骤: 在二进制中我

界王拳十倍 574

JVM系列(八)——对象实例化及直接内存

对象实例化及直接内存

zql1455890112的博客 177

jvm直接内存

直接内存是 Java 中一种基于操作系统内存的区域,直接分配在操作系统内存中,而不是在 JVM 的堆中。直接内存不受 JVM 垃圾回收机制的管理,因此分配和释放都需要由程序员手动完成。通过操作系统提供的malloc等接口分配内存区域。Java 的java.nio包引入了ByteBuffer类,支持直接内存分配,用于提升 I/O 操作性能。直接内存是 JVM 内存模型中的重要组成部分,主要用于提升 I/O 性能和减少内存拷贝。

Flying_Fish_roe的博客 1935

JVM对象实例化过程

JVM对象的实例化 从字节码文件看创建对象的过程 判断对象对应的类是否加载、链接、初始化 虚拟机遇到一条new指令,首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化。如果没有,那么在双亲委派模式下,使用当前类加载器已ClassLoader+包名+类名为Key进行查找对应的.class文件。如果没有找到文件,则抛出ClassNotFoundException异常,如果找到,则进行类加载,并生成对应的Class类对象

anying5823的博客 1869

JVM学习上篇内存与垃圾回收之七对象实例化及直接内存

解析对象实例化流程,以及对象实例在内存中访问图示,着重介绍对象主要由对象头、实例数据和对齐填充组成;对象头主要由运行时元数据、类型指针组成;运行时元数据由偏移线程ID、偏移时间戳、GC分代年龄、哈希值、线程持有锁信息以及锁状态标识组成。

CharlesYan的博客 299

JVM_07 运行时数据区4-对象的实例化内存布局与访问定位+直接内存

大厂面试题? 美团: 对象在jvm 中怎么存储的? 对象头信息里面有哪些东西? 蚂蚁金服: 二面: java对象里面有什么? 1.对象的实例化 1.1 创建对象的方式 new 最常见的方式 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 Class的newInstance():反射的方式,只能调用空参的构造器,权限必须是public Constructor的newInstance(Xxx):反射的方式,可以调用空参、带参的构造器,权限没有要求 使用clon

1708

对象实例化内存布局与访问定位和直接内存

目录对象实例化面试题对象创建方式创建对象的步骤判断对象对应的类是否加载、链接、初始化为对象分配内存处理并发问题初始化分配到的内存设置对象的对象头执行init方法进行初始化对象实例化的过程对象内存布局对象头运行时元数据类型指针实例数据(Instance Data)说明小结对象的访问定位图示对象访问的两种方式句柄访问优点直接指针(HotSpot采用)直接内存 Direct Memory非直接缓存区和缓存区存在的问题 对象实例化 面试题 对象在JVM中是怎么存储的? 对象头信息里面有哪些东西? Java对象头有

hu_zhi_chao的博客 249
上一篇: JVM学习笔记八:方法区
下一篇: JVM学习笔记十:执行引擎
种花途。
博客等级 码龄10年 3粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值