Java对象分配过程以及面试题

news2024/11/15 4:42:44

public static void main(String[] args) {
  	Math math = new Math();
  	math.compute();
}

对于Math类来说,他还有一个类对象, 如下代码所示: 

Class<? extends Math> mathClass = math.getClass();

        这个类对象是存储在哪里的呢?这个类对象是方法区中的元数据对象么?不是的。这个类对象实际上是jvm虚拟机在堆中创建的一块和方法区中源代码相似的信息。如下图堆空间右上角。

堆中的类对象和在方法区中的类元对象有什么区别呢?

        类的元数据信息是放在方法区的。堆中的类信息,可以理解为是类装载后jvm给java开发人员提供的方便的访问类的信息

        通过类的反射我们知道,我们可以通过Math的class拿到这个类的名称,方法,属性,继承关系,接口等等。我们知道jvm的大部分实现是通过c++实现的,jvm在拿到Math类的时候,他不会通过堆中的类信息(上图堆右上角math类信息)拿到,而是直接通过类型指针找到方法区中元数据实现的,这块类型指针也是c++实现的。在方法区中的类元数据信息都是c++获取实现的。

        而我们java开发人员要想获得类元数据信息是通过堆中的类信息获得的,堆中的class类是不会存储元数据信息的。我们可以把堆中的类信息理解为是方法区中类元数据信息的一个镜像。

        Klass Pointer类型指针的含义:Klass不是class,class pointer是类的指针;而Klass Pointer指的是底层c++对应的类的指针


JVM大对象(直接在老年代分配)定义

  • 大对象到底多大:-XX:PreTenureSizeThreshold=n (仅适用于 DefNew / ParNew新生代垃圾回收器
  • G1回收器的大对象判断,则依据Region的大小(-XX:G1HeapRegionSize)来判断,如果对象大于Region50%以上,就判断为大对象Humongous Object

TLAB 分配

        TLAB,全称Thread Local Allocation Buffer, 即:线程本地分配缓存。这是一块线程专用的内存分配区域。TLAB占用的是eden区的空间在TLAB启用的情况下(默认开启),JVM会为每一个线程分配一块TLAB区域。

为什么需要TLAB?

这是为了加速对象的分配。

由于对象一般分配在堆上,而堆是线程共用的,因此可能会有多个线程在堆上申请空间,而每一次的对象分配都必须线程同步,会使分配的效率下降。

考虑到对象分配几乎是Java中最常用的操作,因此JVM使用了TLAB这样的线程专有区域来避免多线程冲突,提高对象分配的效率。

  • 局限性: TLAB空间一般不会太大(占用eden区),所以大对象无法进行TLAB分配,只能直接分配到堆 Heap上。

什么是逃逸

 判断一个对象是否是逃逸对象,就看这个对象能否被外部对象访问到

public class Test {

    public User test1() {
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }

    public void test2() {
        User user = new User();
        user.setId(2);
        user.setName("李四");
    }
}

      Test里有两个方法,test1()方法构建了user对象,并且返回了user,返回回去的对象肯定是要被外部使用的。这种情况就是user对象逃逸出了test1()方法。

        而test2()方法也是构建了user对象,但是这个对象仅仅是在test2()方法的内部有效,不会在方法外部使用,这种就是user对象没有逃逸。

逃逸分析

        定义:逃逸分析(Escape Analysis)简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术。

        就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为参数传递到其他地方中。

  逃逸分析的 JVM 参数如下

  • 开启逃逸分析:-XX:+DoEscapeAnalysis
  • 关闭逃逸分析:-XX:-DoEscapeAnalysis
  • 显示分析结果:-XX:+PrintEscapeAnalysis

   逃逸分析技术在 Java SE 6u23+ 开始支持,并默认设置为启用状态,可以不用额外加这个参数。

逃逸分析优化

        针对上面第三点,当一个对象没有逃逸时,可以得到以下几个虚拟机的优化。

1) 锁消除

        我们知道线程同步锁是非常牺牲性能的,当编译器确定当前对象只有当前线程使用,那么就会移除该对象的同步锁。

        例如,StringBuffer 和 Vector 都是用 synchronized 修饰线程安全的,但大部分情况下,它们都只是在当前线程中用到,这样编译器就会优化移除掉这些锁操作。

锁消除的 JVM 参数如下:

  • 开启锁消除:-XX:+EliminateLocks
  • 关闭锁消除:-XX:-EliminateLocks

锁消除在 JDK8 中都是默认开启的,并且锁消除都要建立在逃逸分析的基础上。

2) 标量替换

        首先要明白标量和聚合量,基础类型和对象的引用可以理解为标量,它们不能被进一步分解。而能被进一步分解的量就是聚合量,比如:对象。

        对象是聚合量,它又可以被进一步分解成标量,将其成员变量分解为分散的变量,这就叫做标量替换。这样,如果一个对象没有发生逃逸,那压根就不用创建它,只会在栈或者寄存器上创建它用到的成员标量,节省了内存空间,也提升了应用程序性能

        标量替换的 JVM 参数如下:

  • 开启标量替换:-XX:+EliminateAllocations
  • 关闭标量替换:-XX:-EliminateAllocations
  • 显示标量替换详情:-XX:+PrintEliminateAllocations

        标量替换同样在 JDK8 中都是默认开启的,并且都要建立在逃逸分析的基础上。

3) 栈上分配

        当对象没有发生逃逸时,该对象就可以通过标量替换分解成成员标量分配在栈内存中,和方法的生命周期一致,随着栈帧出栈时销毁,减少了 GC 压力,提高了应用程序性能

为什么要分配在栈上?

        通过JVM内存模型中,我们知道Java的对象都是分配在堆上的。当堆空间(新生代或者老年代)快满的时候,会触发GC,没有被任何其他对象引用的对象将被回收。如果堆上出现大量这样的垃圾对象,将会频繁的触发GC,影响应用的性能。(分配在堆上,频繁GC,影响效率

        其实这些对象都是临时产生的对象,如果能够减少这样的对象进入堆的概率,那么就可以成功减少触发GC的次数了。我们可以把这样的对象放在堆上,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力(分配在栈上,随着栈帧销毁,不用垃圾回收,提高效率)。

什么情况下会分配在栈上?

        为了减少临时对象在堆内分配的数量,JVM通过逃逸分析确定该对象会不会被外部访问。如果不会逃逸可以将该对象在栈上分配内存。随栈帧出栈而销毁,减轻GC的压力

参考文献:

JVM 对象分配过程 - 掘金

8.JVM内存分配机制超详细解析 - 腾讯云开发者社区-腾讯云

原创|面试官:Java对象一定分配在堆上吗? - 腾讯云开发者社区-腾讯云

Java中的对象都是在堆上分配的吗? - 腾讯云开发者社区-腾讯云

面试问我 Java 逃逸分析,瞬间被秒杀了。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/188029.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将nodejs文件打包成exe, 并设置开机自启动(没有黑窗口)

nodejs打包成exe 使用node的pkg包 # 安装pkg npm install -g pkg # 使用pkg打包, 该命令会同时编译 linux, win, mac 版的exe pkg server.js # 只打包win版 pkg -t win server.js如果安装pkg后提示 pkg不是内部命令, 重新打开cmd窗口再试,如果还提示,则需要配置环境变量 查看…

力扣刷题记录——796. 旋转字符串、884. 两句话中的不常见单词、1046. 最后一块石头的重量

本专栏主要记录力扣的刷题记录&#xff0c;备战蓝桥杯&#xff0c;供复盘和优化算法使用&#xff0c;也希望给大家带来帮助&#xff0c;博主是算法小白&#xff0c;希望各位大佬不要见笑&#xff0c;今天要分享的是——《力扣刷题记录——796. 旋转字符串、884. 两句话中的不常…

五金行业:强行业性的进销存系统具体看三项

很多五金的中小企业&#xff0c;都是从小作坊、个体户做大&#xff0c;普遍有着规模小&#xff0c;管理方式传统&#xff0c;行业内部管理水平偏低等缺陷。从年初忙到年尾&#xff0c;经营者也不清楚是赚是亏&#xff0c;竞争力不强&#xff0c;很多五金企业只要用上管理软件&a…

【HBase高级】1.重要工作机制(1)——读数据流程、数据存储流程

1. 重要工作机制 1.1 读数据流程 1.从zookeeper找到meta表的region的位置&#xff0c;然后读取meta表中的数据。而meta中又存储了用户表的region信息 ZK&#xff1a;/hbase/meta-region-server&#xff0c;该节点保存了meta表的region server数据 2.根据namespace、表名和row…

Elasticsearch:理解 query_string 和 simple_query_string 查询

针对很多的开发者来说&#xff0c;如果你不是很熟悉 DSL 查询&#xff0c;那么在有些情况下&#xff0c;query_string 及 simple_query_string 变得非常灵活及方便。在今天的文章中&#xff0c;我来比较一下这两种查询的方法。 准备数据 我们先使用 _bulk 命令创建如下的一个索…

Go语言入门学习(一)——变量,类型,运算符

Go语言入门学习&#xff08;一&#xff09;——变量&#xff0c;类型&#xff0c;运算符 最近看了蔡超老师与极客邦合作的Go语言学习教程&#xff0c;让我这个之前学java一知半解的我收获颇丰&#xff0c;所以想借此机会把自己的学习历程记录下来&#xff0c;以供后续的查阅 一…

【HoloLens 2 应用开发】自定义手部骨架可视化

推荐微信阅读&#xff1a;【HoloLens 2 应用开发】自定义手部骨架可视化 关闭默认可视化 首先关闭默认的手部可视化&#xff0c;详见上文。 添加预制件 首先&#xff0c;在场景中添加一个 sphere 的 GameObject 对象作为手部关节的预制件。 然后&#xff0c;在场景中添加一个…

CentOS7 网卡bondvlan bond

网卡bonding简介网卡绑定就是把多张物理网卡通过软件虚拟成一个虚拟的网卡&#xff0c;配置完毕后&#xff0c;所有的物理网卡的ip和mac将会变成相同的。多网卡同时工作可以提高网络速度&#xff0c;还可以实现网卡的负载均衡、冗余。bonding模式round-robin(mode0)轮转策略&am…

Docker - 3. 镜像常用命令 docker images、search、pull、rmi

目录 1. 帮助命令 2. 镜像命令 2.1 docker images [选项]&#xff1a;查看所有镜像、仓库、标签和大小 2.2 docker search [选项] 镜像名字&#xff1a;在 Docker Hub 中搜索镜像 2.3 docker pull 镜像名字[:tag]&#xff1a;下载镜像&#xff0c;tag为指定的版本 2.4 d…

MySQL索引特性

文章目录MySQL索引特性索引的概念认识磁盘磁盘的结构磁盘的随机访问&#xff08;Random Access&#xff09;与连续访问&#xff08;Sequential Access&#xff09;MySQL与磁盘交互的基本单位索引的理解观察主键索引现象推导主键索引结构的构建索引结构可以采用哪些数据结构聚簇…

PCI设备的访问方法_桥设备(type1)

PCI设备的访问方法_桥设备(type1) 文章目录PCI设备的访问方法_桥设备(type1)参考资料&#xff1a;一、 硬件结构二、 PCI设备类别及配置方法2.1设备类别2.2 配置设备时怎么选中它三、 配置示例3.1 示例&#xff1a;配置PCI Agent设备3.2 示例&#xff1a;配置PCI桥3.3 示例&…

ThinkPad R490电脑开机之后无限重启怎么重装系统?

ThinkPad R490电脑开机之后无限重启怎么重装系统&#xff1f;有用户使用ThinkPad R490电脑正常开机的情况下&#xff0c;出现了系统自动重启的情况&#xff0c;无法正常的使用电脑了。遇到这个情况怎么去重装一个新的电脑系统&#xff0c;恢复正常使用呢&#xff1f;来看看以下…

九种查找算法-红黑树

红黑树 2-3查找树能保证在插入元素之后能保持树的平衡状态&#xff0c;最坏情况下即所有的子节点都是2-node&#xff0c;树的高度为lgn&#xff0c;从而保证了最坏情况下的时间复杂度。但是2-3树实现起来比较复杂&#xff0c;于是就有了一种简单实现2-3树的数据结构&#xff0…

MySQL 数据库练习题记录02

文章目录前言一、数据库基础1.1 sql练习题1.2 sql语句执行顺序1.3 sql语句编写前言 本文主要记录B站视频视频链接的内容&#xff0c;做到知识梳理和总结的作用&#xff0c;项目git地址。 一、数据库基础 1.1 sql练习题 user表数据: idusername1张三2李四3王五4小刘 user_r…

代码随想录算法训练营第32天 回溯算法 java :491.递增子序列 46.全排列47.全排列 II

文章目录LeetCode 491.递增子序列题目详解注意难点示意图LeetCode 46.全排列题目讲解难点LeetCode47.全排列 II题目讲解示图难点总结LeetCode 491.递增子序列 题目详解 注意难点 在题目中有涉及到 子集序列中至少有两个元素 可以用来进行判断 在单层遍历之前需要声明一个数组…

统计学必备基础知识

一&#xff0c;统计学分为两种&#xff1a;1.描述性统计 2.推断性统计 1.统计数据的类型 (1).计量尺度分为3类&#xff1a;分类数据&#xff0c;顺序数据&#xff0c;数值型数据 分类数据&#xff1a;文字表达数据 顺序数据&#xff1a;非数据型数据&#xff0c;顺序数据…

【swagger】spring security中 swagger2,swagger3和knife4j集成的区别 真的弄懂了吗?

文章目录导包正确方式swagger2在security中放行swagger3在security中放行knife4j放行失败原因分析&#xff1a;swagger访问失败原因分析&#xff1a;作为一个强迫症重度的程序猿 不想多导一个jar包 本文创作背景是鉴于网上大多数是旧版本swagger2的教程&#xff0c;且没有针对2…

【数据结构初阶】第五篇——栈和队列

栈 栈的概念及结构 栈的实现 栈的初始化 销毁栈 入栈 出栈 获取栈顶元素 检测栈是否为空 获取栈中有效元素个数 队列 队列的概念和结构 队列的实现 队列的初始化 销毁队列 入队 出队 获取对头元素 获取队尾元素 判断队列是否为空 获取队列中元素个数 栈 栈…

13.包装类、正则表达式、Arrays类、常见算法、Lambda表达式

目录 一.包装类 1.1 什么是包装类 1.2 包装类的作用 1.3 自动装箱和自动拆箱 1.3.1 自动装箱 1.3.2 自动拆箱 1.4 包装类的特有功能 二.正则表达式 2.1 什么是正则表达式 2.2 正则表达式的规定字符 2.3 字符串对象匹配正则表达式的方法 2.4 正则表达式在字符串方法中…

21特征值和特征向量

特征值与特征向量初探 给定矩阵A&#xff0c;矩阵A乘以向量x&#xff0c;就像是使用矩阵A作用在向量x上&#xff0c;最后得到新的向量Ax。在这里&#xff0c;矩阵A就像是一个函数&#xff0c;接受一个向量x作为输入&#xff0c;给出向量Ax作为输出。 在这一过程中&#xff0c…