如何理解JVM本地方法栈&堆

这期内容当中小编将会给大家带来有关如何理解JVM本地方法栈&堆,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

创新互联建站主营耒阳网站建设的网络公司,主营网站建设方案,app开发定制,耒阳h5小程序定制开发搭建,耒阳网站营销推广欢迎耒阳等地区企业咨询

今天我们一起了解一下关于本地方法栈和Java堆的相关知识。

 
本地方法栈

本地方法栈与Java虚拟机栈发挥的作用相同,区别在于Java虚拟机栈是为虚拟机执行Java方法服务,而本地方法栈是为虚拟机执行Native方法服务。

 
Java堆

Java堆是虚拟机管理的最大的一块内存区域,堆主要用来存放对象的实例。Java堆主要分为:

  • 新生代(Eden)
  • 老年代
  • Survivor(s0、s1也可以成为from、to,属于新生代)

在绝大数情况下,对象都会被分配在新生代,在经历过一次新生代回收后,如果对象还存活那么会进入s0或者s1,每经过一次新生代回收,如果对象存活那么他的年龄将会加,当对象的年龄到达一定的条件时会进入老年代。当然如果对象非常大,超出了新生代的大小,对象也有可能直接分配在老年代。

随着JIT编译器的发展以及逃逸分析技术的成熟,栈上分配、标量替换等技术使得对象分配在堆中变得不再那么绝对。

 
栈上分配

栈上分配是指对那些线程私有的对象可以将他们打散分散在栈上,分配在栈上的好处是随着函数调用结束对象自动销毁,不需要垃圾回收器的介入,从而提高系统的性能。

栈上分配的基础是要进行逃逸分析,逃逸分析的目的是判断对象的作用域是否可能逃出函数体。

逃逸分析只有在Server模式下才可以启动(这个作者由于本人Java环境是Server环境,没有做验证,如果有读者感兴趣,可以使用Client模式启动做一下验证然后截图留言)。参数是:

  • -XX:+DoEscapeAnalysis
public class EscapeAnalysis {
   public static class User {        private int id = 1;        private String name = "xiaoming";    }
   public static void alloc() {        User u = new User();        u.id = 5;        u.name = "xiaohong";    }
   public static void main(String[] args) {        long start = System.currentTimeMillis();        for (int i = 0; i < 100000000; i++) {            alloc();        }        long end = System.currentTimeMillis();        System.out.println(end - start);    }}
 

执行以下命令将源码文件编译成字节码文件并且运行字节码

javac -d . EscapeAnalysis.javajava -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGC jvm/heap/EscapeAnalysis
 

由于Java8默认开启了逃逸分析,所以我们用-XX:-DoEscapeAnalysis移除逃逸分析看一下效果。

如何理解JVM本地方法栈&堆  


通过上图我们发现由于对象分配在堆上,但我们指定的最大堆为10m,不够存储我们大量User对象,因此虚拟机需要不停的进行垃圾回收来释放堆空间,程序执行时间928ms。

下面我们通过-XX:-EliminateAllocations将标量替换关闭,也就是说不允许对象打散分配在栈上。

java -server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:-EliminateAllocations -XX:+PrintGC jvm/heap/EscapeAnalysis
 
如何理解JVM本地方法栈&堆  


当我们关闭标量替换以后,会发现对象依旧不能在栈上分配。

下面让我们看一下当我们打开逃逸分析和标量替换(允许Use对象的id和name当做局部变量在栈上存储时)执行效果:

java -server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+EliminateAllocations -XX:+PrintGC jvm/heap/EscapeAnalysis
 
如何理解JVM本地方法栈&堆  


通过上图可以看出,我们的程序只进行了一次垃圾回收,总运行时间5ms,相比之前接近1s中的运行时间性能翻了将近200倍,可见由于栈上分配的优化,使得小对象可以直接分配在栈上,避免了垃圾回收器的介入,大幅度提高了我们程序的性能。

栈上分配需要同时开启逃逸分析和标量替换,Java8 Server模式下这两个参数都是默认开启的。

上述就是小编为大家分享的如何理解JVM本地方法栈&堆了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注创新互联行业资讯频道。


名称栏目:如何理解JVM本地方法栈&堆
当前路径:http://ybzwz.com/article/jgseog.html