Java虚拟机-逃逸分析(Escape Analysis)和栈上分配

简介: Java虚拟机-逃逸分析(Escape Analysis)和栈上分配

 image.gif编辑

 

我们都知道Java中的对象默认都是分配到堆上,在调用栈中,只保存了对象的指针。当对象不再使用后,需要依靠GC来遍历引用树并回收内存。如果堆中对象数量太多,回收对象还有整理内存,都会会带来时间上的消耗,GC表示压力很大,然后影响性能。所以,在我们日常开发中,内存,时间都是相当的宝贵,该如何优化堆栈开销,是一个比较重要的问题。

逃逸分析(Escape Analysis)和栈上分配是对JVM进行优化的常规手段,本文主要深入了解一下。

一、概念

1.逃逸

当变量(或者对象)在方法中分配后,其指针有可能被返回或者被全局引用,这样就会被其他方法或者线程所引用,这种现象称作指针(或者引用)的逃逸(Escape)。通俗点讲,如果一个对象的指针被多个方法或者线程引用时,那么我们就称这个对象的指针(或对象)的逃逸(Escape)。

具体而言,分为方法逃逸和线程逃逸两种。

方法逃逸:在一个方法体内,定义一个局部变量,而它可能被外部方法引用,比如作为调用参数传递给方法,或作为对象直接返回。或者,可以理解成对象跳出了方法。

线程逃逸:这个对象被其他线程访问到,比如赋值给了实例变量,并被其他线程访问到了。对象逃出了当前线程。

2.栈上分配

主要是指在Java程序的执行过程中,在方法体中声明的变量以及创建的对象,将直接从该线程所使用的栈中分配空间。 就是把没发生逃逸的对象,在栈上分配空间。一般而言,创建对象都是从堆中来分配的,这些对象是有可能发生逃逸的。

3.逃逸分析

是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。

在JDK 6之后支持对象的栈上分析和逃逸分析,在JDK 7中完全支持栈上分配对象。 其是否打开逃逸分析依赖于以下JVM的设置:

#强制开启:    
-server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m
#关闭逃逸分析:    
-server -XX:-DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m

image.gif

二、为什么需要逃逸分析和栈上分配?

为了GC性能。GC主要回收的对象是堆和方法区。GC不会对栈、程序计数器这些进行回收的,因为没东西可以回收。

如果方法逃逸,那么对象就会分配在堆中,这个时候,GC就要工作了。如果没发生方法逃逸,那么对象就分配在栈中,当方法结束后,资源就自动释放了,GC压根不用操心。所以方法逃逸就是为GC来服务的。GC不运行的时候,程序的性能肯定会好点,不会占用程序运行的时间。虽然GC清扫垃圾的速度很快,但是当一个程序足够大的时候,对象就自然多了,垃圾也自然多了,这个时候GC就忙了。

而进行逃逸分析,就是把那些不会发生逃逸的对象直接分配在栈中,这样不需要GC参与资源的释放,性能自然就会有提升了。

三、 逃逸分析和栈上分配的优劣势分析

1.优势

同步消除:线程同步的代价是相当高的,同步的后果是降低并发性和性能。逃逸分析可以判断出某个对象是否始终只被一个线程访问,如果只被一个线程访问,那么对该对象的同步操作就可以转化成没有同步保护的操作,这样就能大大提高并发程度和性能。

标量替换:逃逸分析方法如果发现对象的内存存储结构不需要连续进行的话,就可以将对象的部分甚至全部都保存在CPU寄存器内,这样能大大提高访问速度。

2.劣势

栈上分配受限于栈的空间大小,一般自我迭代类的需求以及大的对象空间需求操作,将导致栈的内存溢出;故只适用于一定范围之内的内存范围请求。

四、参数配置一览

逃逸分析在JDK6U23以上都是默认开启的,开启后会极大地提升性能。

-XX:+DoEscapeAnalysis开启逃逸分析(JDK 6u23以上默认开启)
-XX:-DoEscapeAnalysis 关闭逃逸分析
#标量替换基于分析逃逸基础之上,开启标量替换必须开启逃逸分析
-XX:+EliminateAllocations开启标量替换(jdk1.8默认开启,其它版本未测试)
-XX:-EliminateAllocations 关闭标量替换
#锁消除基于分析逃逸基础之上,开启锁消除必须开启逃逸分析
-XX:+EliminateLocks开启锁消除(jdk1.8默认开启,其它版本未测试)
-XX:-EliminateLocks 关闭锁消除

image.gif

五、总结

    1. 能在方法内创建对象,就不要再方法外创建对象。毕竟这是为了GC好,也是为了提高性能。
    2. 栈上分配可以提升代码性能,降低在多线程情况下的锁使用,但是会受限于其空间的大小。
    3. 逃逸分析的效果只能在特定场景下,满足高频和高数量的小容量的变量分配结构,才是合适的。

    参考资料:

      1. https://www.jianshu.com/p/3ecc626ce304
      2. JVM的栈上分配与逃逸分析(Escape Analysis)_bladestone的博客-CSDN博客
      3. JVM的逃逸分析 - 阿两君 - 博客园
      4. https://www.jianshu.com/p/04fcd0ea5af7
      相关文章
      |
      7天前
      |
      监控 Java 开发者
      Java一分钟之-Java性能分析与调优:JProfiler, VisualVM等工具
      【5月更文挑战第21天】本文介绍了Java性能优化的两个利器——JProfiler和VisualVM。JProfiler通过CPU Profiler、内存分析器和线程视图帮助解决过度CPU使用、内存泄漏和线程阻塞问题;VisualVM则聚焦于GC行为调整和类加载优化,以减少内存压力和提高应用性能。使用这些工具进行定期性能检查,是提升Java应用效率的关键。
      25 0
      |
      13天前
      |
      存储 Java
      深入理解Java虚拟机:JVM内存模型
      【4月更文挑战第30天】本文将详细解析Java虚拟机(JVM)的内存模型,包括堆、栈、方法区等部分,并探讨它们在Java程序运行过程中的作用。通过对JVM内存模型的深入理解,可以帮助我们更好地编写高效的Java代码,避免内存溢出等问题。
      |
      1天前
      |
      Java 索引
      Java数据结构——栈
      Java数据结构——栈
      13 1
      |
      4天前
      |
      存储 分布式计算 Java
      深入探究JAVA编程语言:概念、应用与实例分析
      **JAVA**是广泛应用的高级编程语言,以其易学性、跨平台能力和高效的性能著称。它采用面向对象编程,强调封装、继承和多态,且具备平台无关性、内置安全性和多线程支持。JAVA广泛应用于Web开发(如JSP、Servlet)、移动应用(Android开发)、大数据处理(Hadoop、Spark)和桌面应用。通过一个计算两数之和的简单示例,展示了JAVA的易读性和面向对象特性,帮助读者理解JAVA在实际开发中的运用。
      |
      4天前
      |
      算法 搜索推荐 Java
      Java数据结构 -- 常见算法分析(查找算法、排序算法)精解详解!!!
      Java数据结构 -- 常见算法分析(查找算法、排序算法)精解详解!!!
      7 0
      |
      8天前
      |
      算法 Java 编译器
      从Java字节码到JIT编译器,深入理解Java虚拟机
      Java虚拟机(JVM)是Java程序运行的关键。想深入理解Java虚拟机,我们需要了解Java字节码、类加载机制、垃圾回收算法、JIT编译器等方面的知识。本文将介绍这些关键知识点,并通过示例代码加深理解。
      |
      13天前
      |
      Java 关系型数据库 MySQL
      【Java Spring开源项目】新蜂(NeeBee)商城项目运行、分析、总结
      【Java Spring开源项目】新蜂(NeeBee)商城项目运行、分析、总结
      167 4
      |
      13天前
      |
      Java
      【Java多线程】分析线程加锁导致的死锁问题以及解决方案
      【Java多线程】分析线程加锁导致的死锁问题以及解决方案
      28 1
      |
      13天前
      |
      存储 监控 Java
      JVM工作原理与实战(十七):运行时数据区-栈内存溢出
      JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了栈内存溢出、设置虚拟机栈的大小等内容。
      16 0
      |
      13天前
      |
      存储 监控 安全
      JVM工作原理与实战(十六):运行时数据区-Java虚拟机栈
      JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了运行时数据区、Java虚拟机栈等内容。
      15 0