Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java对象一定分配在堆上吗?

Java对象一定分配在堆上吗?

作者头像
阿珍
发布于 2024-11-04 06:51:27
发布于 2024-11-04 06:51:27
21102
代码可运行
举报
运行总次数:2
代码可运行

1. 引入

首先回答标题中的问题:Java对象一定会被分配到堆上吗?答案是:不一定

Java中创建的对象一般会分配到堆上,当堆空间不足时,就会触发GC进行垃圾回收,但是GC次数太多会影响程序的性能。

在编译期间,编译器会对代码做很多优化,为了减少内存分配压力,JVM提供了一项重要优化技术:逃逸分析。逃逸分析得出的结论为后续优化措施提供依据。

2. 什么是逃逸分析

逃逸分析Escape Analysis):JVM提供的一种优化技术,用于分析对象会不会发生逃逸。

Q:如何理解逃逸? 逃逸可以理解为会不会在作用域范围外被调用。如:一个方法内定义的变量,会不会在这个方法外被使用,如果否,则认为未逃逸;如果是:则认为会发生逃逸,这就是方法逃逸

根据上述的理解,可以分为不同的逃逸方式。对象的逃逸程度从高到低

  • 线程逃逸:一个对象在方法内被定义后,可能被外部线程访问,如:赋值给可以在其他线程中访问的实例变量;
  • 方法逃逸:一个对象在方法内被定义后,可能会被外部方法引用;
  • 不逃逸:仅在作用域范围内使用。

根据逃逸分析的结果来决定优化策略

3. 优化策略

3.1 栈上分配(Stack Allocations

  • 将对象分配到上,对象占用的内存空间可以随着栈帧出栈(即方法的结束)而销毁,这样垃圾收集的压力会下降很多。
  • 整个过程通过判断对象,来决定其是否必须要存在堆上,如果不需要的话,则可以被分配到栈上,栈随着线程的消逝而消逝,这样能够减少了GC的频率,从而提高性能。
  • 栈上分配支持方法逃逸,不支持线程逃逸

【例如】

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Java 代码解读复制代码public void test(){
    Student s = new Student();
    s.setName("张三");
    s.setAge(22);
    System.out.println(s.getAge());
}

逃逸分析后得出的结论为:不逃逸,对象s只作用于该方法内,不会被其他方法/线程引用,所以该对象可以分配到上。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Java 代码解读复制代码public Student test(){
    Student s = new Student();
    s.setName("张三");
    s.setAge(22);
    return s;
}

该方法的返回值为Student对象,逃逸分析后,得出的结论是:对象s可能会被其他方法/线程引用,所以该对象只能分配到上。

3.2 标量替换(Scalar Replacement

Q:什么是标量? 标量可以理解为:不可拆解的数据,如:intlong等数值类型。 与之相对的概念为聚合量(Aggregate:即可以拆解的数据,如:Java中的对象

标量替换就是将Java对象拆散,根据程序访问的情况,将其用到的成员变量恢复到原始类型来访问。

这样做的好处:对象的成员变量在栈上分配和读写;为后续进一步优化创造条件。可以将标量替换看作栈上分配的一种特例,实现更加简单,但对逃逸的要求更高,不允许对象逃逸出方法范围内

【例如】

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Java 代码解读复制代码//标量替换前的代码
public static void main(String[] args) {
   User user =  new User("张三",33);
   System.out.println("姓名:" + s.getName() + " 年龄:" + s.getAge());
}

// 标量替换后的代码
public static void main(String[] args) {
   String name = "张三";
   int age = 33;
   System.out.println("姓名:" + name + " 年龄:" + age);
}

3.3 同步消除(Synchronization Elimination

线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,无法被其他线程访问,那么这个变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以安全消除掉。

如果JVM通过逃逸分析,发现一个对象只能从一个线程访问到,访问这个对象时可以不加同步锁,如:如果程序中使用了synchronized锁,JVM会将synchronized锁消除。

4. Java对象内存分配流程

image.png
image.png

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
原创|面试官:Java对象一定分配在堆上吗?
最近在看 Java 虚拟机方面的资料,以备工作中的不时之需。首先我先抛出一个我自己想的面试题,然后再引出后面要介绍的知识点如逃逸分析、标量替换、栈上分配等知识点
每天晒白牙
2020/08/21
1.4K0
原创|面试官:Java对象一定分配在堆上吗?
对象并不一定都是在堆上分配内存的
关于JVM的内存结构及内存分配方式,不是本文的重点,这里只做简单回顾。以下是我们知道的一些常识:
爱撸猫的杰
2019/03/28
7150
Java对象竟然会在栈上分配内存?
JVM中高深的优化技术,如同类继承关系分析,该技术并非直接去优化代码,而是一种为其他优化措施提供依据的分析技术。
JavaEdge
2021/03/23
7150
Java对象竟然会在栈上分配内存?
再清楚不过了,JVM逃逸分析,你一定得知道
提到JVM,相信大家一定知道JVM是什么?但是,提到逃逸分析,相信大多数人都可能一脸懵逼,逃逸分析到底是什么呢?接下来给大家分享一下。
Java程序猿阿谷
2020/12/16
2.4K0
再清楚不过了,JVM逃逸分析,你一定得知道
JVM的栈上分配与逃逸分析(Escape Analysis)
JVM中较前沿的优化技术,它与类型继承关系分析一样,并非直接优化代码,而是为其他优化措施提供依据的分析技术。
JavaEdge
2021/02/22
1.3K0
【性能优化】面试官:Java中的对象和数组都是在堆上分配的吗?
https://github.com/sunshinelyz/mykit-delay
冰河
2020/10/29
2.2K0
【性能优化】面试官:Java中的对象和数组都是在堆上分配的吗?
Java的对象一定是在堆上分配的嘛?谁这么说就直接用“逃逸分析”反驳他!
之前在和朋友聊天的时候,他突然问我什么是“逃逸分析”。说实话当时我还真不太能完整的讲出什么是逃逸分析。这玩意虽然我看八股的时候经常遇见,但之前还真没专项学习过。因此我们今天来完整的介绍一下什么是逃逸分析。
程序员牛肉
2025/01/22
910
Java的对象一定是在堆上分配的嘛?谁这么说就直接用“逃逸分析”反驳他!
jvm之逃逸分析解读
在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis)后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。这也是最常见的堆外存储技术。 
一个风轻云淡
2023/10/15
2290
虚拟机--逃逸分析
如果对象发生逃逸,那会分配到堆中。(因为对象发生了逃逸,就代表这个对象可以被外部访问,换句话说,就是可以共享,能共享数据的,无非就是堆或方法区,这里就是堆。)
终码一生
2022/04/14
4400
JVM 对象分配过程
逃逸分析(Escape Analysis)简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术。
斯武丶风晴
2020/05/09
1.1K0
JVM 对象分配过程
JVM之堆
约定:新生区 <–> 新生代 <–> 年轻代 、 养老区 <–> 老年区 <–> 老年代、 永久区 <–> 永久代
Java微观世界
2025/01/20
1280
JVM之堆
JVM堆
堆针对一个JVM进程来说是唯一的,也就是一个进程只有一个JVM,但是进程包含多个线程,他们是共享同一堆空间的。
麋鹿大哥
2020/08/19
4000
JVM之堆
一个进程对应一个jvm实例,同时包含多个线程,这些线==程共享方法区和堆==,每个==线程独有程序计数器、本地方法栈和虚拟机栈==。
程序员阿杜
2021/06/29
9210
3分钟搞清楚 JVM逃逸分析
作为一个合格java开发者都知道,基本上所有对象都是在堆上创建。但是,这里还是没有把话说绝对哈,指的是基本上所有。
田维常
2023/02/27
3870
3分钟搞清楚 JVM逃逸分析
逃逸分析:分离对象、标量替换、同步锁消除
在JVM的实现中,为了提高JVM的性能和节省内存空间,JVM提供了一种叫做“逃逸分析”的特性,而且对于“逃逸分析”这种特性,也是近年来大厂面试常问的知识点。今天,我们就一起来聊聊什么是逃逸分析。
冰河
2024/01/17
2030
逃逸分析:分离对象、标量替换、同步锁消除
面试题24:什么是栈上分配?
并不是所有对象都分配在堆上,除了堆(绝⼤多数对象分配到堆上)以外,还有两个地⽅可以存放对象——栈和TLAB。
爪哇缪斯
2023/05/09
3950
面试题24:什么是栈上分配?
逃逸分析(Escape Analysis)技术
背景:随着jvm的发展,堆已经不是分配内存的唯一选择了,还有栈上分配、标量替换优化技术。
逍遥壮士
2021/04/29
1.3K0
逃逸分析(Escape Analysis)技术
不敢相信?System.currentTimeMillis() 存在性能问题
为了防止歧义,可以换个说法:Java对象实例和数组元素都是在堆上分配内存的吗? 答:不一定。满足特定条件时,它们可以在(虚拟机)栈上分配内存。
挨踢小子部落阁
2019/11/24
5870
jvm内存模型、jvm内存结构、Java内存结构、Java内存模型(JMM)、Java对象模型的区别(吐血研究整理)
JVM内存模型则是指JVM的内存分区。jvm内存模型 == jvm内存结构 == Java内存结构!!!汉语虽然博大精深,但是也经常会因为命名很雷同让人懵逼或者混淆不清。
全栈程序员站长
2022/08/25
4.4K1
jvm内存模型、jvm内存结构、Java内存结构、Java内存模型(JMM)、Java对象模型的区别(吐血研究整理)
JVM内存分配机制之栈上分配与TLAB的区别
在java开发中,我们普遍认知中,new出的对象是直接分配到堆空间中,而实际情况并非如此,其实大家伙可以思考一下,无论方法的生命周期长与短,只要new的对象就存放在堆中,那么这样只会对jvm的gc产生一个比较大的负担 而前几天在看到jvm调优书中有说到,new出来的对象并非所有都存在堆内存中,其实还有其他另外两个地方可以进行存储new出的对象,称之为栈上分配和TLAB
黎明大大
2020/11/24
2.4K0
JVM内存分配机制之栈上分配与TLAB的区别
相关推荐
原创|面试官:Java对象一定分配在堆上吗?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验