JVM 调优篇8 调优案例5- 逃逸分析

news/2024/9/21 21:46:16 标签: jvm

一 逃逸分析

1.1 概念

  • 逃逸分析的基本行为就是分析对象动态作用域:
  • 当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。
  • 当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。例如作为调用参数传递到其他地方中。逃逸分析(Escape Analysis)-CSDN博客

1.2 作用

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

1.3 案例

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

public class EscapeAnalysis {

    public EscapeAnalysis obj;

    /*
    方法返回EscapeAnalysis对象,发生逃逸
     */
    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 useEscapeAnalysis1(){
        EscapeAnalysis e = getInstance();
        
    }
}

二  逃逸分析作用案例

2.1 栈上分配

2.1.1 作用

1.栈上分配,将堆分配转化为栈分配。如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。可以减少垃圾回收时间和次数。

2.1.2  不使用逃逸分析

1.代码  

参数:-Xmx1G -Xms1G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

public class StackAllocation {
    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) + " ms");
        // 为了方便查看堆内存中对象个数,线程sleep
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }


    private static void alloc() {
        User user = new User();
    }

    static class User {

    }
}

2.分析:-Xmx1G -Xms1G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

2.1.3  使用逃逸分析

参数:

2.2 标量替换

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

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

案例:

public static void main(String[] args) {
    alloc();
  }  
  private static void alloc() {
    Point point = new Point(1,2);
    System.out.println("point.x="+point.x+"; point.y="+point.y);
  }
  class Point{
    private int x;
    private int y;
  }

以上代码中,point对象并没有逃逸出alloc方法,并且point对象是可以拆解成标量的。那么,JIT就会不会直接创建Point对象,而是直接使用两个标量int x ,int y来替代Point对象。

  以上代码,经过标量替换后,就会变成:

private static void alloc() {
    int x = 1;
    int y = 2;
    System.out.println("point.x="+x+"; point.y="+y);
  }

Point这个聚合量经过逃逸分析后,发现他并没有逃逸,就被替换成两个标量了。

好处:就是可以大大减少堆内存的占用。因为一旦不需要创建对象了,那么就不再需要分配堆内存了。

标量替换为栈上分配提供了很好的基础。

2.3 锁消除

即时编译器(Just-in-time Compilation,JIT)可以借助逃逸分析来判断同步块所使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果同步块所使用的锁对象通过这种分析被证实只能够被一个线程访问,那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的同步。这个取消同步的过程就叫同步省略,也叫锁消除。

public void f() {
  Object hollis = new Object();
  synchronized(hollis) {
    System.out.println(hollis);
  }
}

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

public void f() {
  Object hollis = new Object();
  System.out.println(hollis);
}

在使用synchronized的时候,如果JIT经过逃逸分析之后发现并无线程安全问题的话,就会做锁消除。

  -XX:+EliminateLocks开启锁消除(jdk1.8默认开启,其它版本未测试) 
  -XX:-EliminateLocks 关闭锁消除 
  锁消除基于分析逃逸基础之上,开启锁消除必须开启逃逸分析

http://www.niftyadmin.cn/n/5669499.html

相关文章

【PHP代码审计】PHP常见配置解析

&#x1f31d;博客主页&#xff1a;菜鸟小羊 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 php.ini配置文件 php函数禁用 disable_functions该选项可以设置哪些php函数是禁止使用的&#xff0c;重启生效&#xff0…

精通Prompt技巧:GitHub精选指南

更丰富的prompt技巧–from GitHub 前言 关于prompt的东西我已经写过不止一篇文章了&#xff0c;感兴趣的朋友可以去之前的文章看看&#xff0c;但是当我真正认真去研究并在GitHub上学习全球这些先进的优秀的prompt资料时我依然收获满满&#xff0c;有的我之前闻所未闻&#x…

Linux系统中文件I/O

在Linux系统中&#xff0c;文件I/O&#xff08;输入/输出&#xff09;是操作系统与硬件交互的基石&#xff0c;它涵盖了从磁盘读取数据到内存&#xff0c;以及从内存写数据到磁盘的过程。深入理解Linux的文件I/O机制&#xff0c;不仅对于系统管理员优化系统性能至关重要&#x…

【垃圾识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目选题+TensorFlow+图像识别

一、介绍 垃圾识别分类系统。本系统采用Python作为主要编程语言&#xff0c;通过收集了5种常见的垃圾数据集&#xff08;‘塑料’, ‘玻璃’, ‘纸张’, ‘纸板’, ‘金属’&#xff09;&#xff0c;然后基于TensorFlow搭建卷积神经网络算法模型&#xff0c;通过对图像数据集进…

python-SZ斐波那契数列/更相减损数

一&#xff1a;SZ斐波那契数列题目描述 你应该很熟悉斐波那契数列&#xff0c;不是吗&#xff1f;现在小理不知在哪里搞了个山寨版斐波拉契数列&#xff0c;如下公式&#xff1a; F(n) { $\ \ \ \ \ \ \ \ \ \ \ \ $ a,( n1) $\ \ \ \ \ \ \ \ \ \ \ \ $ b,( n2) $\ \ \ \ \ \ …

老程序员的数字游戏开发笔记(二) —— 直接开始一个Godot项目

目录 本篇简述 一个最简单的Godot项目 创建一个新项目 创建一个 Sprite2D 节点 创建Gd脚本-GDScript 添加打印 运行项目 加个旋转 让它前进 监听输入 查看帮助 再添加按“上”键时移动 总结 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收…

【linux】快速列出 systemctl 特定名的服务

在 Linux 系统管理中,我们经常需要查看和管理各种系统服务。systemd 是最新的 Linux 系统和服务管理器,它提供了一个强大的命令行工具 systemctl 来管理系统服务。今天,我们就来聊聊如何使用 systemctl 配合 grep 命令来快速查找指定名称的服务。 systemctl -a | grep name这个…

RabbitMQ 高级特性——发送方确认

文章目录 前言发送方确认confirm 确认模式return 退回模式 常见面试题 前言 前面我们学习了 RabbitMQ 中交换机、队列和消息的持久化&#xff0c;这样能够保证存储在 RabbitMQ Broker 中的交换机和队列中的消息实现持久化&#xff0c;就算 RabbitMQ 服务发生了重启或者是宕机&…