JVM中TLAB(Thread Local Allocation Buffer)+逃逸分析

news2025/1/8 12:21:11

1、为什么有TLAB(Thread Local Allocation Buffer)

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

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

  • 为避免多个线程操作同一地址,需要使用加锁等机制,进而影响分配速度。

总结一句话:堆上存放的对象实例多线程不安全,并且影响分配速度。如果能将对象实例分配在独立的一块区域,那就能解决多线程不安全和分配速度慢问题,这就是TLAB。

2、什么是TLAB

  • 从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域,它包含在Eden空间内。

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

  • 据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计。

3、TLAB使用

  • 尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选。

  • 在程序中,开发人员可以通过选项“-XX:UseTLAB”设置是否开启TLAB空间(默认是开启的)。

  • 默认情况下,TLAB空间的内存非常小,仅占有整个Eden空间的1%,当然我们可以通过选项 “-XX:TLABWasteTargetPercent” 设置TLAB空间所占用Eden空间的百分比大小。

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

4、通过逃逸分析判断对象实例可能被优化成栈上分配

如何将堆上的对象分配到栈,需要使用逃逸分析手段。

在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述:

随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。

在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis)后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配(TLAB).。这样就无需在堆上分配内存,也无须进行垃圾回收了。这也是最常见的堆外存储技术。

此外,基于OpenJDK深度定制的TaoBaoVM,其中创新的GCIH(GC invisible heap)技术实现off-heap,将生命周期较长的Java对象从heap中移至heap外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC的回收频率和提升GC的回收效率的目的。

5、逃逸分析概述

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

通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。

逃逸分析的基本行为就是分析对象动态作用域:

  • 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。

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

发生逃逸和未发生逃逸实例

public class EscapeAnalysis {

    public EscapeAnalysis obj;

    /**
     * 方法返回EscapeAnalysis对象,发生逃逸
     * @return
     */
    public EscapeAnalysis getInstance() {
        return obj == null ? new EscapeAnalysis() : obj;
    }

    /**
     * 为成员属性赋值,发生逃逸
     */
    public void setObj() {
        this.obj = new EscapeAnalysis();
    }

    /**
     * 对象的作用于仅在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis() {
        EscapeAnalysis e = new EscapeAnalysis();
    }

    /**
     * 引用成员变量的值,发生逃逸
     */
    public void useEscapeAnalysis2() {
        EscapeAnalysis e = getInstance();
    }
}

没有发生逃逸的对象,则可以分配到栈上,随着方法执行的结束,栈空间就被移除(这种主动释放内存的方式相比堆内对象等待GC要更好)。

6、逃逸分析设置

参数设置:

在JDK 6u23 版本之后,HotSpot中默认就已经开启了逃逸分析

这个默认大前提是启用了-server模式,当然JVM默认也是-server模式

如果使用的是较早的版本,开发人员则可以通过:

  • 选项“-XX:+DoEscapeAnalysis"显式开启逃逸分析

  • 通过选项“-XX:+PrintEscapeAnalysis"查看逃逸分析的筛选结果

怎么判断是否启用了逃逸分析呢?

  • a、通过jps 查看当前应用进程

  • b、通过jinfo -flag DoEscapeAnalysis 进程号

如果结果是“-XX:-DoEscapeAnalysis”则为未启用,如果是“-XX:+DoEscapeAnalysis”则启用了

7、代码实例比对启用逃逸分析和非逃逸分析

下述代码在主函数中进行了1亿次alloc。调用进行对象创建,User实例的创建作用域未出方法,如果启用逃逸分析,则会启用TLAB。咱们看下启用和不启用逃逸分析,执行时间和堆内对象使用情况。

/**
 * @author liuchao
 * @date 2023/2/24
 */
public class Test {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            alloc();
        }
        // 查看执行时间
        long end = System.currentTimeMillis();
        System.out.println("花费时间:" + (end - start));
        // 方便查看堆内存中对象个数,线程sleep
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public static void alloc() {
        //未发生逃逸
        User user = new User();
    }

}

class User {
    private int age;
    private String userName;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

7.1、启用逃逸分析

默认就启用了,不需要配置,直接看执行结果。

7.2、不启用逃逸分析

配置vm选项:-XX:-DoEscapeAnalysis

查看执行结果

7.3、结论

相同的代码,启用逃逸分析进行1亿次alloc用时7ms,堆上User对象实例占比37%;

不启用逃逸分析进行1亿次alloc用时70ms,堆上User对象实例占比93%;

可以看出相差巨大,所以啊开发中能使用局部变量的,就不要使用在方法外定义。

8、逃逸分析的缺点

关于逃逸分析的论文在1999年就已经发表了,但直到JDK1.6才有实现,而且这项技术到如今也并不是十分成熟。

其根本原因就是无法保证逃逸分析的性能消耗一定能高于他的消耗。虽然经过逃逸分析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复杂的分析的,这其实也是一个相对耗时的过程。

一个极端的例子,就是经过逃逸分析之后,发现没有一个对象是不逃逸的。那这个逃逸分析的过程就白白浪费掉了。

虽然这项技术并不十分成熟,但是它也是即时编译器优化技术中一个十分重要的手段。

注意到有一些观点,认为通过逃逸分析,JVM会在栈上分配那些不会逃逸的对象,这在理论上是可行的,但是取决于JVM设计者的选择。据我所知,Oracle Hotspot JVM中并未这么做,这一点在逃逸分析相关的文档里已经说明,所以可以明确所有的对象实例都是创建在堆上。

目前很多书籍还是基于JDK7以前的版本,JDK已经发生了很大变化,intern字符串的缓存和静态变量曾经都被分配在永久代上,而永久代已经被元数据区取代。但是,intern字符串缓存和静态变量并不是被转移到元数据区,而是直接在堆上分配,所以这一点同样符合前面一点的结论:对象实例都是分配在堆上。

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

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

相关文章

java地图导出——添加经纬线

概述 前面的文章Node实现切片的拼接和地图的导出和Java实现地图的导出分别讲述可如何在node和java中实现切片的拼接以及地图的导出。本文&#xff0c;书接前文&#xff0c;实现java导出时经纬度的添加。 实现后效果 实现 完整的实现思路流程如下图&#xff1a; 1. 根据切片…

什么是Makefile?如何编写Makefile?

&#x1f947;今日学习目标&#xff1a;什么是Makefile&#xff1f;如何编写Makefile&#xff1f; &#x1f935;‍♂️ 创作者&#xff1a;JamesBin ⏰预计时间&#xff1a;10分钟 &#x1f389;个人主页&#xff1a;嵌入式悦翔园个人主页 &#x1f341;专栏介绍&#xff1a;L…

RabbitMQ实现死信队列

目录死信队列是什么怎样实现一个死信队列说明实现过程导入依赖添加配置编写mq配置类添加业务队列的消费者添加死信队列的消费者添加消息发送者添加消息测试类测试死信队列的应用场景总结死信队列是什么 “死信”是RabbitMQ中的一种消息机制&#xff0c;当你在消费消息时&#…

单调栈(C/C++)

目录 1. 单调栈的定义 2. 单调栈的常见用途 3. 案例分析 3.1 暴力解法 3.2 单调栈 4. 单调栈总结 1. 单调栈的定义 单调栈顾名思义&#xff0c;就是栈内的元素是单调的。根据栈内元素的单调性的不同&#xff0c;可以分为&#xff1a; 单调递增栈&#xff1a;栈内元素是单…

LeetCode 105. 从前序与中序遍历序列构造二叉树 106. 从中序与后序遍历序列构造二叉树

为什么前序和中序或者中序和后序&#xff0c;两两组合能构建一个二叉树&#xff1f; 因为前序和后序可以确定根&#xff0c;而中序可以划分出左右区间。 文章目录从前序与中序遍历序列构造二叉树从中序与后序遍历序列构造二叉树从前序与中序遍历序列构造二叉树 难度 中等 题目链…

基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文

1.3 系统实现的功能 本次设计任务是要设计一个超市进销存系统&#xff0c;通过这个系统能够满足超市进销存系统的管理及员工的超市进销存管理功能。系统的主要功能包括&#xff1a;首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 …

TS泛型,原来就这?

一、泛型是什么&#xff1f;有什么作用&#xff1f; 当我们定义一个变量不确定类型的时候有两种解决方式&#xff1a; 使用any 使用any定义时存在的问题&#xff1a;虽然知道传入值的类型但是无法获取函数返回值的类型&#xff1b;另外也失去了ts类型保护的优势 使用泛型 泛型…

记一次线上es慢查询导致的服务不可用

现象 某日线上业务同学反馈订单列表查询页面一直loding&#xff0c;然后提示请求超时&#xff0c;几分钟之后恢复正常 接到报障之后&#xff0c;马上根据接口URL&#xff0c;定位到了请求链路&#xff0c;发现是es查询超时&#xff0c;这里我们的业务订单表数据是由几百万的&a…

【数据结构】时间复杂度和空间复杂度以及相关OJ题的详解分析

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录1.算法效率1.1 如何衡…

独家 | Gen-1——可以改变视频风格的AI模型

翻译&#xff1a;吴振东校对&#xff1a;张睿毅本文约1000字&#xff0c;建议阅读3分钟 本文简单介绍了Runway公司的发展史&#xff0c;以及他们新推出的生成式AI模型Gen-1&#xff0c;可用于通过应用文本提示或者参考图像所指定的任意风格&#xff0c;将现有视频转换为新视频。…

php mysql高校教材管理系统

我的目标就是在于开发一个功能实用、操作方便&#xff0c;简单明了的管理系统&#xff1b;其能够录入教师个人的信息&#xff0c;教导主任信息&#xff0c;在操作上能够完成诸如添加、修改、删除、按各种条件进行查询、等方面的工作&#xff0c;基本满足学校的日常业务的需求. …

System V|共享内存基本通信框架搭建|【超详细的代码解释和注释】

前言 那么这里博主先安利一下一些干货满满的专栏啦&#xff01; 手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm1001.2014.3001.5482这里包含了博主很多的数据结构学习上的总结&#xff0c;每一篇都是超级用心编写的&#xff0c;有兴趣的伙伴们都支…

string和自动推断类型

欢迎来观看温柔了岁月.c的博客目前设有C学习专栏C语言项目专栏数据结构与算法专栏目前主要更新C学习专栏&#xff0c;C语言项目专栏不定时更新待C专栏完毕&#xff0c;会陆续更新C项目专栏和数据结构与算法专栏一周主要三更&#xff0c;星期三&#xff0c;星期五&#xff0c;星…

【项目管理】项目进度管理中的逻辑关系

项目的进度管理是项目核心管理之一&#xff0c;通过合理的进度安排&#xff0c;制定出科学可行的分项工期表&#xff0c;并条理清晰的显示出项目进度之间的逻辑关系。 1、目标是计划的灵魂 进度计划必须按照确定的项目总进度要求进行编制&#xff0c;了解项目总目标和整体安…

网络安全——数据链路层安全协议(2)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.局域网数据链路层安全协议 1.IEEE 802.10 &#xff08;1&#xff09;IEE…

JavaWeb HTTP和Maven

4、Http 4.1、什么是HTTP HTTP&#xff08;超文本传输协议&#xff09;是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上。 文本&#xff1a;html&#xff0c;字符串&#xff0c;~ ….超文本&#xff1a;图片&#xff0c;音乐&#xff0c;视频&#xff0c;定位&am…

登峰造极,师出造化,Pytorch人工智能AI图像增强框架ControlNet绘画实践,基于Python3.10

人工智能太疯狂&#xff0c;传统劳动力和内容创作平台被AI枪毙&#xff0c;弃尸尘埃。并非空穴来风&#xff0c;也不是危言耸听&#xff0c;人工智能AI图像增强框架ControlNet正在疯狂地改写绘画艺术的发展进程&#xff0c;你问我绘画行业未来的样子&#xff1f;我只好指着Cont…

jdbc模板的基本使用

1.JdbcTemplate的开发步骤 <1>导入spring-jdbc和spring-tx坐标 <2>创建数据库表和实体 <3>创建JdbcTemplate对象 <4>执行数据库 2.JdbcTemplate快速入门 <1>导入坐标 <dependency><groupId>org.springframework</groupId><…

【Python学习笔记】第十七节 Python 异常处理

Python 异常在任何一种编程语言中&#xff0c;都会有异常处理机制&#xff0c;python也不例外&#xff0c;它提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。Python 异常处理异常的概念&#xff1a;在程序运行过程中&#xff0c;由于代码错误或者运行环境…

Java数据结构与算法——手撕LRULFU算法

LRU算法 力扣146&#xff1a;https://leetcode-cn.com/problems/lru-cache/ 讲解视频&#xff1a;https://www.bilibili.com/video/BV1Hy4y1B78T?p65&vd_source6f347f8ae76e7f507cf6d661537966e8 LRU是Least Recently Used的缩写&#xff0c;是一种常用的页面置换算法&…