JVM05_堆的概述、内存结构、复制算法、Minor|Major|Full GC、私有区域TLAB、对象分配、参数总结、逃逸分析、栈上分配、锁消除、标量替换(四)

简介: ⑩①. 栈上分配⑩②. 同步替换 锁消除⑩③. 分离对象或标量替换

⑩①. 栈上分配


  • ①. JIT编译器在编译期间根据逃逸分析的结果,发现如果一个对象并没有逃逸出方法的话,就可能被优化成栈上分配


  • ②.代码举例


/**
 * 栈上分配测试
 * -Xmx256m -Xms256m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails
 */
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(1000000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }
    private static void alloc() {
        User user = new User(); //未发生逃逸
    }
    static class User {
    }
}


③. 未开启逃逸分析的情况


-Xmx256m -Xms256m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails


日志打印发生了GC
[GC (Allocation Failure) [PSYoungGen: 65536K->560K(76288K)] 65536K->568K(251392K), 0.0017179 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 66096K->464K(76288K)] 66104K->480K(251392K), 0.0017602 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
花费的时间为: 74 ms


微信图片_20220106141129.png


④. 开启逃逸分析的情况


-Xmx256m -Xms256m -XX:+DoEscapeAnalysis -XX:+PrintGCDetails


日志打印:并没有发生 GC,耗时 3ms ,栈上分配是真的快啊
花费的时间为: 4 ms


image.png


⑩②. 同步替换 锁消除


  • ①. 从JIT角度看相当于无视它了,这个锁对象没有被共享给其他线程


②. 例如下面的智障代码,根本起不到锁的作用


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


public void f() {
    Object hellis = new Object();
    synchronized(hellis) {
        System.out.println(hellis);
    }
}
// JIT会将它变成这样
public void f() {
    Object hellis = new Object();
    System.out.println(hellis);
}


③. 注意:字节码文件中并没有进行优化,可以看到加锁和释放锁的操作依然存在,同步省略操作是在解释运行时发生的


微信图片_20220106141331.png


⑩③. 分离对象或标量替换


①. 标量(scalar)是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量


②. 相对的,那些还可以分解的数据叫做聚合量(Aggregate),Java中的对象就是聚合量,因为他可以分解成其他聚合量和标量


③. 在JIT阶段,如果经过逃逸分析,发现一个对象不会被外界访问的话,那么经过JIT优化,就


会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换


④. 举列子


public static void main(String args[]) {
    alloc();
}
class Point {
    private int x;
    private int y;
}
private static void alloc() {
    Point point = new Point(1,2);
    System.out.println("point.x" + point.x + ";point.y" + point.y);
}
//以上代码,经过标量替换后,就会变成
private static void alloc() {
    int x = 1;
    int y = 2;
    System.out.println("point.x = " + x + "; point.y=" + y);
}
相关文章
|
17小时前
|
缓存 Java
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
8 0
|
1天前
|
Java UED 开发者
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
JVM逃逸分析原理解析:优化Java程序性能和内存利用效率
|
2天前
|
存储 安全 Java
深入理解Java内存模型(JMM)与虚拟机的内存结构(JVM)
深入理解Java内存模型(JMM)与虚拟机的内存结构(JVM)
|
2天前
|
存储 算法 安全
JVM-内存划分-垃圾回收器-回收算法-双亲委派-三色标记
JVM-内存划分-垃圾回收器-回收算法-双亲委派-三色标记
|
3天前
|
存储 缓存 算法
JVM对象创建与内存分配机制
该类对应的java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
10 0
|
1天前
|
存储 缓存 算法
详解JVM内存优化技术:压缩指针
详解JVM内存优化技术:压缩指针
|
1天前
|
存储 缓存 监控
深入解析JVM内存分配优化技术:TLAB
深入解析JVM内存分配优化技术:TLAB
|
3天前
|
存储 Java 对象存储
jvm内存模型剖析
当线程cpu时间片执行完后,线程进入休眠状态,当再次唤醒时,通过程序计数器确定指令执行到哪一行,然后继续往下执行。
13 1
|
3天前
|
存储 安全 Java
JVM之内存结构
Java内存结构包括程序计数器、虚拟机栈、本地方法栈、堆和直接内存。程序计数器记录执行地址,线程私有,无溢出。虚拟机栈处理方法调用,局部变量在线程栈中,过深或过大可能导致StackOverflowError。本地方法栈服务于native方法。堆存储对象,线程共享,有垃圾回收。方法区存储类信息,1.8前的永久代,1.8后的元空间,溢出可调整相应参数。运行时常量池包含字符串池,1.6在永久代,1.8在堆,intern方法管理。直接内存用于NIO,提高读写性能,手动回收。
|
4天前
|
存储 Java C++
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据
Java虚拟机(JVM)管理内存划分为多个区域:程序计数器记录线程执行位置;虚拟机栈存储线程私有数据,如局部变量和操作数;本地方法栈支持native方法;堆存放所有线程的对象实例,由垃圾回收管理;方法区(在Java 8后变为元空间)存储类信息和常量;运行时常量池是方法区一部分,保存符号引用和常量;直接内存非JVM规范定义,手动管理,通过Buffer类使用。Java 8后,永久代被元空间取代,G1成为默认GC。
11 2