内容简介:栈上分配是JVM的一个优化选项。Java的对象一般都是分配在堆内存中的,而JVM开启了栈上分配后,允许把线程私有的对象(其它线程访问不到的对象)打散分配在栈上。这些分配在栈上的对象在方法调用结束后即自行销毁,不需要JVM触发垃圾回收器来回收,因此提升了JVM的性能。栈上分配在
栈上分配是JVM的一个优化选项。
Java的对象一般都是分配在堆内存中的,而JVM开启了栈上分配后,允许把线程私有的对象(其它线程访问不到的对象)打散分配在栈上。这些分配在栈上的对象在方法调用结束后即自行销毁,不需要JVM触发垃圾回收器来回收,因此提升了JVM的性能。
栈上分配在 JDK6u23 后默认是开启了的。下面通过代码来验证这一点。
验证
写一段代码:
public class OnStackTest { // User类 public static class User{ public int id=0; public String name=""; } // 创建User类对象 public static void alloc(){ User u=new User(); u.id=5; u.name="geym"; } // 程序入口 public static void main(String[] args) throws InterruptedException { long b=System.currentTimeMillis(); // 创建大量的对象 for(int i=0;i<99999999;i++){ alloc(); } long e=System.currentTimeMillis(); // 打印执行时间 System.out.println(e-b); } } 复制代码
在 JDK6u22 环境下执行的结果:
-Xmx
:指定最大堆内存
-Xms
:指定最大堆内存
-XX:+PrintGC
:打印GC日志, +
号表示启用, -
号表示禁用
D:\develop\jdk\6u22\bin\java.exe -Xmx5m -Xms5m -XX:+PrintGC geym.zbase.ch2.onstackalloc.OnStackTest [GC 2048K->288K(5824K), 0.0049399 secs] [GC 2336K->288K(5824K), 0.0013872 secs] [GC 2336K->320K(5824K), 0.0026034 secs] ...... [GC 3280K->720K(6080K), 0.0001026 secs] 3304 复制代码
在 JDK6u23 环境下执行的结果:
D:\develop\jdk\6u23\bin\java.exe -Xmx5m -Xms5m -XX:+PrintGC geym.zbase.ch2.onstackalloc.OnStackTest 70 复制代码
从以上两个执行的结果可以看出,JDK6u22默认是没有开启栈上分配的,所以 alloc()
方法中new出来的User对象,是存放在堆上的。由于指定了最大堆内存只有5m,当堆内存不足就会触发GC。从JDK6u22的GC日志可以看出执行过程频繁触发GC,执行耗时3304,明显比JDK6u23的长。
而JDK6u23的执行过程中没有打印任何GC日志,证明这时候 alloc()
方法中new出来的User对象,是存放在 alloc()
方法对应的栈帧上的。当每一次执行 alloc()
方法,线程会向 Java 栈压入一个栈帧, new User()
创建的对象就存放在这个栈帧上; alloc()
方法执行结束,栈帧从Java栈弹出,user对象随栈帧的弹出销毁。
示意图:
相关JVM参数
在 JDK6u22及之前的版本 如果需要使用栈上分配来优化,可以加入以下参数:
java -server -Xmx5m -Xms5m -XX:+PrintGC -XX:+DoEscapeAnalysis -XX:-UseTLAB -XX:+EliminateAllocations geym.zbase.ch2.onstackalloc.OnStackTest 复制代码
-XX:+DoEscapeAnalysis
:开启逃逸分析
-XX:-UseTLAB
:禁用TLAB(Thread Local Allocation Buffer)
-XX:+EliminateAllocations
:开启标量替换
关于逃逸分析
逃逸分析的作用就是判断一个对象的作用域有没有可能逃出一个Java方法的作用域。请看下面例子演示:
// u对象逃出alloc的作用域,不符合栈上分配的条件 public class OnStackTest { private static User u; public static void alloc(){ u=new User(); } } 复制代码
// u对象没有逃出alloc的作用域,符合栈上分配的条件 public class OnStackTest { public static void alloc(){ User u=new User(); } } 复制代码
关于标量替换
启用标量替换后,允许把对象打散分配在栈上。 比如user对象有id和name属性,在启用标量替换后,user对象的id和name属性会视为局部变量分配在栈上
注意:逃逸分析和标量替换是栈上分配的前提,所以,在jvm参数中关闭了二者其中一个选项,栈上分配都不会生效。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 操作系统学习笔记-11:内存分配(一):连续分配
- 操作系统学习笔记-12:内存分配(二):非连续分配
- PHPKafka 1.1.1 发布,支持消费者分区分配策略之粘性分配等功能
- Go:内存管理分配
- 多机任务分配机制
- Allocations分析内存分配
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据库系统概念
Abraham Silberschatz、Henry F. Korth、S. Sudarshan / 杨冬青、马秀莉、唐世渭 / 机械工业 / 2006-10-01 / 69.50元
本书是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、得克萨斯大学、康奈尔大学、伊利诺伊大学、印度理工学院等都采用本书作为教科书。我国也有许多所大学采用本书以前版本的中文版作为本科生和研究生的数据库课程的教材和主要教学参考书,收到了良好的效果。 本书调整和新增内容:调整了第4版的讲授顺序。首先介绍SQL及其高级特性,使学生容易接受数据库设计的概念。新增数据库设计的专......一起来看看 《数据库系统概念》 这本书的介绍吧!