探究跨代引用和逃逸分析如何提升程序性能!

简介: 探究跨代引用和逃逸分析如何提升程序性能!


🍊 跨代引用

在Java虚拟机中,跨代引用指的是老年代中的对象引用了年轻代中的对象。当进行年轻代的垃圾回收时,需要扫描老年代中所有引用年轻代的对象,在老年代里面做大量的遍历和扫描操作,这是非常消耗性能的。为了优化这个问题,JVM引入了记忆集(Card Table)的抽象数据结构。

记忆集记录了从非收集区域指向收集区域的一个指针集合,这个指针集合是由一组连续的内存卡片(Card)组成的。每个内存卡片的大小是2^18个字节,可以理解为一个内存页面。记忆集能够记录指向年轻代的内存卡片中所有的指针,将这些指针标记为"dirty"。在minor gc时,只需要扫描"dirty"的内存卡片,而不是扫描老年代中所有引用年轻代的对象。

思路比较清晰,现在来看一下这个问题的示例代码:

public class CrossGenerationReferenceExample {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        Object obj = new Object();
        for (int i = 0; i < 1000000; i++) {
            list.add(obj);
        }
    }
}

这个示例代码中的问题在于,对象obj在年轻代中创建,但是被放到了老年代中的ArrayList里面。这个时候,当进行年轻代的垃圾回收时,就需要扫描老年代中所有引用年轻代的对象,而且这个ArrayList还是一个非常大的对象,扫描的效率非常低下。

现在来看一下使用记忆集优化之后的代码:

public class CrossGenerationReferenceExample {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        Object obj = new Object();
        for (int i = 0; i < 1000000; i++) {
            list.add(obj);
            if (i % 20000 == 0) {
                System.gc();
            }
        }
    }
}

在这个示例代码中,每添加20000个对象就手动执行一次垃圾回收操作。这个操作会强制触发记忆集的更新,即将内存卡片中的指针标记为"dirty"。这样,在下一次垃圾回收时,就只需要扫描"dirty"的内存卡片,提高了垃圾回收的效率。

🍊 逃逸分析

逃逸分析是Java虚拟机优化的重要手段之一,它可以通过静态分析来确定对象的动态作用域,判断一个对象是否会“逃逸”,即被其他方法或线程引用。如果对象不会逃逸,则可以将对象的创建和销毁都放在栈上进行,从而减少在堆上进行内存分配和回收的开销。

逃逸分析有三种程度:从不逃逸、方法逃逸和线程逃逸。这三个由低到高表示不同逃逸的程度。

🎉 栈上分配

在Java虚拟机中,堆中的对象对于所有线程都是可见的,只要持有这个对象的引用,就可以访问到堆中存储的对象数据。虚拟机的垃圾回收子系统会回收堆中不再使用的对象,但是回收动作无论是标记筛选出可回收对象,还是回收和整理内存,都需要耗费大量资源。

如果确定一个对象不会逃逸出线程之外,那让这个对象在栈上分配内存将会是一个很不错的主意,对象所占用的内存空间就可以随栈帧出栈而销毁。在一般应用中,完全不会逃逸的局部对象和不会逃逸出线程的对象所占的比例是很大的,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁,垃圾回收子系统的压力将会下降很多。

栈上分配可以支持方法逃逸,但不能支持线程逃逸。

下面是一个栈上分配的示例代码:

public static void main(String[] args) {
    for (int i = 0; i < 1000000; i++) {
        Point p = new Point(1, 2);
        p.setX(i);
        p.setY(i);
    }
}
class Point {
    private int x;
    private int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void setX(int x) {
        this.x = x;
    }
    public void setY(int y) {
        this.y = y;
    }
}

在这个示例代码中,每次循环都创建一个Point对象,在Point对象的构造函数中将xy初始化。Point对象不会逃逸出方法之外,因此可以将它们分配在栈上。

🎉 标量替换

一个数据已经无法再分解成更小的数据来表示了,Java虚拟机中的原始数据类型(int、long等数值类型及reference类型等)都不能再进一步分解了,那么这些数据就可以被称为标量。

一个数据可以继续分解,那它就被称为聚合量。Java中的对象就是典型的聚合量。如果把一个Java对象拆散,根据程序访问的情况,将其用到的成员变量恢复为原始类型来访问,这个过程就称为标量替换。

假如逃逸分析能够证明一个对象不会被方法外部访问,并且这个对象可以被拆散,那么程序真正执行的时候将可能不去创建这个对象,而改为直接创建它的若干个被这个方法使用的成员变量来代替。

将对象拆分后,除了可以让对象的成员变量在栈上(栈上存储的数据,很大机会被虚拟机分配至物理机器的高速寄存器中存储)分配和读写之外,还可以为后续进一步的优化手段创建条件。标量替换可以视作栈上分配的一种特例,实现更简单(不用考虑整个对象完整结构的分配),但对逃逸程度的要求更高,它不允许对象逃逸出方法范围内。

下面是一个标量替换的示例代码:

public static void main(String[] args) {
    for (int i = 0; i < 1000000; i++) {
        String s = new String("abc" + i);
        int length = s.length();
    }
}

在这个示例代码中,每次循环都创建一个String对象,并取出它的长度。逃逸分析能够证明String对象不会逃逸出方法之外,因此可以将对象的成员变量拆分为一个char数组和一个offset整型变量。在Java虚拟机内部,会把char数组和offset整型变量分别分配在栈上,而不需要在堆上分配String对象。

总之,逃逸分析是一种非常重要的JVM优化手段,能够让JVM能够更好地利用现代计算机的硬件资源,提高程序的性能。通过栈上分配和标量替换等技术,能够在一定程度上减少对堆内存的使用,从而让垃圾回收的效率更高,进而让程序能够更好地使用计算机的内存和CPU资源。


相关文章
|
9月前
|
Java
【逃逸分析】
【逃逸分析】
|
8天前
|
Java UED 开发者
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
|
2月前
|
存储 缓存 Java
深入理解Java中的逃逸分析
深入理解Java中的逃逸分析
67 0
|
2月前
|
算法 安全 Java
【JVM】并发的可达性分析详细解释
【JVM】并发的可达性分析详细解释
|
2月前
|
设计模式 消息中间件 Java
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
面试官:什么是JIT、逃逸分析、锁消除、栈上分配和标量替换?
615 1
|
2月前
|
算法 Java Go
Go语言中的垃圾回收机制:原理、优化与影响
【2月更文挑战第5天】本文深入探讨了Go语言中的垃圾回收机制,包括其工作原理、性能优化方法以及对程序运行的影响。通过了解这些内容,读者可以更好地理解Go语言的内存管理特点,并在实际开发中更好地应对垃圾回收带来的挑战。
|
2月前
|
安全 编译器 C#
C#中的可空引用类型:减少空引用异常的利器
【1月更文挑战第9天】C# 8.0中引入的可空引用类型特性,它通过在编译时提供更精确的静态分析,帮助开发者减少运行时的空引用异常。文章详细阐述了可空引用类型的工作原理、如何配置项目以使用此特性,以及在实际编码中如何利用可空引用类型提升代码的健壮性和可读性。
|
2月前
|
缓存 算法 JavaScript
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
提高Java程序性能!了解可达性分析算法、强软弱虚引用和三色标记GC的过程,避免不可达对象阻碍程序性能!
|
10月前
|
测试技术 编译器 C++
栈局部变量优化探究,意外发现了 vs 的一个 bug ?
栈局部变量优化探究,意外发现了 vs 的一个 bug ?
|
12月前
|
存储 Java 编译器
详细分析Go语言内存逃逸
在Go语言中,内存逃逸是一个重要的概念,它涉及到变量的分配和生命周期管理。理解内存逃逸对于编写高效、可靠的Go代码至关重要。本文将详细讨论Go语言中的内存逃逸,包括其原因、影响和如何进行逃逸分析。
152 0

热门文章

最新文章