首页 > 编程语言 >【 java 安全】Java对象都是堆上分配?看完Java中对象逃逸分析就知道答案了

【 java 安全】Java对象都是堆上分配?看完Java中对象逃逸分析就知道答案了

时间:2024-10-09 14:49:02浏览次数:7  
标签:java name 对象 age dog 逃逸 Java public

原创 龙虾编程

随着JIT编译期的发展与逃逸分析技术逐渐成熟,所有的对象都分配到堆上也渐渐变得不是一定的。在编译期间JIT会对代码做很多优化,其中有一部分优化是减少内存堆分配压力,这里有一种重要的技术叫逃逸分析。逃逸分析是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。

1、方法逃逸和未逃逸

逃逸分析是分析指针动态范围的方法,当对象在方法中分配后,其指针有可能被返回,此时就会被其他方法或者线程所引用到,我们称这种现象为指针 (引用)的逃逸。逃逸分析在jdk1.7之后是默认开启的,控制逃逸分析的参数是:-XX:+DoEscapeAnalysis

(1)方法逃逸

一个对象被创建(new)出来之后,如果是作为参数传递到外部了,那么这个对象被外部所调用,这就是方法逃逸。
如下所示的代码:

public static Dog  getDog(){
  Dog dog = new Dog();
  dog.setName("small dog");
  dog.setAge(2);
  return dog;
}

上面的代码中局部变量dog可能会被外部调用,这个就是方法的逃逸。

(2)未逃逸

与方法逃逸相对的就是方法未逃逸了,如下就是典型的未逃逸:

public static void getDog(){
  Dog dog = new Dog();
  dog.setName("small dog");
  dog.setAge(2);
}

此时的局部变量dog不会被外部引用,所以不会出现方法逃逸。

public static String getDogStr(){
  Dog dog = new Dog();
  dog.setName("small dog");
  dog.setAge(2);
  return dog.toString();
}

此时方法的返回值是一个字符串而不是一个对象的引用,所以这个局部变量dog也不会被外部锁引用,就不是方法逃逸。

2、线程逃逸

public static StringBuffer craeteStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb;
}

sb是一个方法内部变量,在上述代码中直接将其返回出去,这个StringBuffer有可能被其他方法所改变,这样它的作用域就不只是在方法内部,也有可能被外部线程访问到。

典型的如类变量或可以在其他线程中访问的实例变量,可能别其他的而线程访问到,我们称之为线程逃逸。

方法逃逸和线程逃逸他们逃逸强度不一样,如下图所示:

3、逃逸分析意义

(1)对象在栈上分配

如果确定一个对象不会逃逸到线程之外,那么可以考虑将这个对象在栈上分配,对象占用的内存随着栈帧弹出而销毁,这样可以减轻垃圾回收的压力。
如以下图所示的:

Person对象在栈上分配了,此时栈帧3对应的方法调用结束后,就会弹出栈,那么Person对象占用的空间也就随之释放。

(2)同步锁消除

线程同步本身是一个相对耗时的过程,如果逃逸分析能够确定一个变量不会逃逸出线程,那么这个变量的读写肯定就不会有竞争,对这个变量添加的同步锁也就可以安全地消除掉,如下代码:

public void setDog(){
  Object lock = new Object();
  synchronized(lock){
      system.out.println("龙虾编程");
    }
}

上面的代码中对lock对象进行加锁,但是lock对象只在setDog()方法内部并且对象也不会被其他线程调用,所以在JIT编译阶段就会被优化这段代码,如下所示:

public void setDog(){
  Object lock = new Object();
  system.out.println("龙虾编程");
}

在synchronized中,如果JIT经过逃逸分析之后发现代码并没有线程安全问题,就会做锁消除。

(3)标量替换

int a;

这个变量a是基本数据类型,它是不可拆分,我们称之为标量。

public class Dog {
  private int age;
  private String name;
  private Origin orign;
}

相对的,我们还可以分解的对象数据叫做聚合量,Java中的对象就是聚合量(如上的Dog类对象),因为它可以分解成其他标量(age、name)和聚合量(orign)。

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

public static void main(String args[]){
  getDog();
}

public static void getDog(){
  SmallDog smallDog = new SmallDog(1, "smallDog");
  system.out.println("name: " + smallDog.getName() + ", age: " + smallDog.getAge());
}

public class SmallDog {

  private String name;
  private int age;
  
  public SmallDog(int age, String name){
    this.age = age;
    this.name = name;
  }
}

方法getDog()经过逃逸分析发现它中的smallDog对象不会被方法部访问并且这个对象可以被拆散,那么可以不创建对象,直接创建若干个成员变量代替,这样可以让对象的成员变量在栈上分配和读写。优化之后的代码如下所示:

public static void main(String args[]){
  getDog();
}

public static void getDog(){
  //对象的变量替换
  String name = "smallDog";
  iint age = 1;
  
  system.out.println("name: " + name  + ", age: " + age);
}

public class SmallDog {

  private String name;
  private int age;
  
  public SmallDog(int age, String name){
    this.age = age;
    this.name = name;
  }
}

标量替换可以很好的减少堆内存的占用,因为不需要创建对象,就不再需要分配堆内存了。
标量替换默认是没有开启的,如果需要开启标量替换就添加参数-XX:+EliminateAllocations

总结:

(1)逃逸分析可以带来一定程度上的性能优化,但是逃逸分析自身也需要经过一系列的复杂处理,所以需要消耗一定的时间。

(2)不是所有的对象都会在堆上分配空间,也有可能在栈上分配。当JVM通过逃逸分析发现一个对象只在一个方法中使用并且不会逃逸出这个方法,那么它可能会选择在栈上分配这个对象。如果一个对象可以被拆解为一些基本类型或引用类型的字段,并且这些字段都只在一个方法中使用,那么JVM可能会选择进行标量替换,将这个对象拆解并在栈上分配空间。

(3)加锁不一定会生效,因为JIT根据逃逸分析会将锁消除。

(4)逃逸分析分为不逃逸、方法逃逸、线程逃逸,逃逸的强度也是越来越强。

标签:java,name,对象,age,dog,逃逸,Java,public
From: https://www.cnblogs.com/o-O-oO/p/18410657

相关文章

  • java+vue计算机毕设扶贫产品网上订销系统【源码+程序+论文+开题】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和互联网的普及,电子商务已成为推动社会经济发展的重要力量。在扶贫工作中,传统的销售模式往往受限于地域、信息不畅等因素,导致......
  • java计算机毕业设计博恒人力资源规划系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在当今竞争激烈的商业环境中,企业的人力资源管理成为决定其成败的关键因素之一。随着信息技术的飞速发展,传统的人力资源管理方式已难以满足现代企业的......
  • java计算机毕业设计高校学生个性化学习推荐(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在高等教育日益普及的今天,高校学生面临着丰富的课程资源与多样的学习需求。然而,传统的教育模式往往忽视了学生的个性化差异,导致学习效果参差不齐。随......
  • (2024最新毕设合集)基于SpringBoot的乡村书屋小程序-31881|可做计算机毕业设计JAVA、PHP
    摘要随着信息技术的快速发展和互联网的广泛普及,数字化服务的需求不断增长,乡村书屋作为传统的文化服务机构也需要适应这一变革。本研究将使用Java开发技术,通过springboot作为框架,结合微信小程序,和MySQL作为数据存储的技术,开发一套功能齐备可移动的乡村书屋小程序,旨在提升乡......
  • Java之反射
    目录反射定义主要用途反射相关的类Class类中【获得类相关方法】Class类中【获得类中属性相关的方法】 Class类中【获得类中注解相关的方法】  Class类中【获得类中构造器相关的方法】 Class类中【获得类中方法相关的方法】 获得Class对象代码示例1代码示例......
  • Java之String类
    目录初识String字符串比较相等字符串常量池理解字符串的不可变字符与字符串字符串常见操作字符串比较compareTo()函数的原码 字符串查找字符串替换字符串拆分字符串截取其它操作StringBuffer和StringBuilder面试题:请解释String、StringBuffer、StringBuilder......
  • 专栏简介:Java 17 深入剖析:从入门到精通
    Java17深入剖析:从入门到精通专栏简介在信息技术迅猛发展的今天,Java语言凭借其跨平台的特性、强大的生态系统以及丰富的社区支持,依然稳居开发者的首选。随着Java17的发布,Java语言引入了众多创新特性和改进,使得它在现代软件开发中更具优势。本专栏将为读者提供一个深......
  • 【JAVA开源】基于Vue和SpringBoot的医疗病历交互系统
    本文项目编号T072,文末自助获取源码\color{red}{T072,文末自助获取源码}......
  • 一文通Java 锁:锁机制及锁常见问题的深入解析(Java 并发编程(偏向、轻/重量级、读写、可
    在并发编程中,锁机制是保障线程安全的核心工具。锁的类型、使用场景、以及锁引发的种种问题都是开发者在设计高并发系统时必须应对的挑战。本篇博客将围绕锁的类型、应用场景、以及常见的锁问题展开详细讨论,帮助大家深入理解Java锁机制的优缺点与其适用场景。文章目录......
  • PTA JAVA语言 面向对象程序设计 作业二 6-2 定义学生类 定义一个学生类(Student),其中包
    6-2定义学生类分数10作者 fpc 谢谢大佬关注,不定期分享学习笔记,希望大佬能多多支持,三连必回单位 内蒙古师范大学定义一个学生类(Student),其中包括四个属性:姓名(name),年龄(age),班级号(classNo),爱好(hobby)裁判测试程序样例:/*请在这里填写答案*/测试该类的程序如下:publiccl......