结论:个人推荐,变量定义在for循环内部

原因:
1.在10亿次的数量级上,耗时上,两者没有区别
2.用javap进行反汇编后,指令码上基本无区别,所以在执行时也无区别(变量定义在for循环外没有赋值为null时,区别只是临时变量表中的位置不同;并赋值为null时,只是多了一个null压栈和出栈)
2.50.用gc日志彻底粉碎,变量定义在for循环内,会‘循环创建引用,浪费内存’的错误说法
3.jdk源码中,变量定义在for循环内部

过程:
原本用javap分析完反汇编后就可以结束并得出结论
结果我突发奇想打算实际证伪下‘循环创建引用,浪费内存’
然后就有了下面代码中描述的操作,结果分析了半天gc打印的日志,发现两种方式也一样,并没有多出来的‘大量引用占用空间’
但是又发现,gc日志中显示占用的内存空间与预估占用的内存空间不符(预估方式请参考另一篇文档,计算对象的大小:https://blog.csdn.net/jt781861965/article/details/114813576)
后来才突然惊醒到,经过逃逸分析,这些对象都被直接在栈上分配了,并没有在堆上分配,所以也不存在gc的问题(逃逸分析默认是打开的,具体逃逸分析可参考:https://www.cnblogs.com/gnivor/p/6028001.html)

**关闭逃逸分析后,**1000w次的数量级上,耗时上,两者没有区别(相较于开启逃逸分析,差距还是很大);javap进行反汇编后,指令码与开启逃逸分析时无区别;gc日志中显示的占用内存也是一样多,最后通过计算得出一个对象占用17byte(因为有jvm自身消耗的内存,计算存在误差,因此结果与实际的一个User对象16byte吻合)
至此,彻底粉碎了,变量定义在for循环内,会‘循环创建引用,浪费内存’的错误说法

测试代码(vm参数在代码中):

package com.myspringboot.jvm.foru;public class ForUserTest {//开启逃逸分析使用下面的代码//vm参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintGC  -XX:+PrintGCTimeStamps  -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCApplicationStoppedTimepublic static void main(String[] args) {//填充内存byte[] bytes1 = new byte[5 * 1024 * 1024];long start = System.currentTimeMillis();//考虑到业务场景,在for中获取到对象后,没有后续操作的话,没有意义;所以在new完之后,还进行了简单的操作outFor();//inFor();System.out.println(System.currentTimeMillis() - start);//强制gcbyte[] bytes2 = new byte[5 * 1024 * 1024];}public static void outFor() {User user = null;for (int i = 0; i < 999999999; i++) {user = new User();user.setI(i);user.getI();}}public static void inFor() {for (int i = 0; i < 999999999; i++) {User user = new User();user.setI(i);user.getI();}}//分隔线=====================================================================================================//关闭逃逸分析使用下面的代码//vm参数:-server -XX:-DoEscapeAnalysis -verbose:gc -Xms400M -Xmx400M -Xmn300M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintGC  -XX:+PrintGCTimeStamps  -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintGCApplicationStoppedTime
//    public static void main(String[] args) {//        long start = System.currentTimeMillis();
//        //考虑到业务场景,在for中获取到对象后,没有后续操作的话,没有意义;所以在new完之后,还进行了简单的操作
//        outFor();
//        //inFor();
//        System.out.println(System.currentTimeMillis() - start);
//        //强制gc
//        byte[] bytes2 = new byte[200 * 1024 * 1024];
//    }
//
//    public static void outFor() {//        User user = null;
//        for (int i = 0; i < 9999999; i++) {//            user = new User();
//            user.setI(i);
//            user.getI();
//        }
//    }
//
//    public static void inFor() {//        for (int i = 0; i < 9999999; i++) {//            User user = new User();
//            user.setI(i);
//            user.getI();
//        }
//    }
}
package com.myspringboot.jvm.foru;public class User {private int i;public int getI() {return i;}public void setI(int i) {this.i = i;}
}

用javap对class文件进行反汇编:

javap -c -l -v ForUserTest.class

运行时常量池

outFor()

inFor()

对其中的outFor()方法的反汇编指令码进行了解释

         0: aconst_null
(将null压栈)
(栈:null)1: astore_0
(弹出,将null放到局部变量表‘0’位置)
(栈:)
(局部变量表‘0’位置:null)2: iconst_0
(将0压栈)
(栈:0)3: istore_1
(弹出,将0放到局部变量表‘1’位置)
(栈:)
(局部变量表‘1’位置:0)4: iload_1
(将局部变量表‘1’位置的值压栈)
(栈:0)5: ldc           #8                  // int 999999999
(将运行时常量池中8位置的值999999999压栈)
(栈:0,999999999)7: if_icmpge     34
(弹出栈中中的两个值,并进行比较,当局部变量表‘1’位置的值大于等于999999999时,跳转到34行开始执行;否则接着顺序执行)
(栈:)10: new           #9                  // class com/myspringboot/jvm/foru/User
(从运行时常量池中9位置的值找到class对象,分配空间,类属性赋初始值后压栈)
(栈:0xFF(引用地址))13: dup
(将栈顶的元素复制,并重新压栈(此时栈中有两个相同的元素))
(栈:0xFF,0xFF)14: invokespecial #10                 // Method com/myspringboot/jvm/foru/User."<init>":()V
(从运行时常量池中10位置的值找到init方法,弹出一个元素,对类属性赋默认值,并执行构造方法)
(栈:0xFF)17: astore_0
(弹出,将0xFF放到局部变量表‘0’位置)
(栈:)18: aload_0
(将局部变量表‘0’位置的值压栈)
(栈:0xFF)19: iload_1
(将局部变量表‘1’位置的值压栈)
(栈:0xFF,0)20: invokevirtual #11                 // Method com/myspringboot/jvm/foru/User.setI:(I)V
(从运行时常量池中11位置的值找到setI方法,弹出两个元素,执行setI方法,因为没有返回值,所以不需要压栈)
(栈:)23: aload_0
(将局部变量表‘0’位置的值压栈)
(栈:0xFF)24: invokevirtual #12                 // Method com/myspringboot/jvm/foru/User.getI:()I
(从运行时常量池中12位置的值找到getI方法,弹出一个元素,执行getI方法,并将结果压栈)
(栈:0)27: pop
(将栈顶元素弹出)
(栈:)28: iinc          1, 1
(将局部变量表‘1’位置的值加1,注意此操作没有压栈、弹出的动作)
(栈:)31: goto          4
(转到4)34: return
(返回)

开启逃逸分析的vm参数和gc日志

关闭逃逸分析的vm参数和gc日志

变量定义在for循环外面还是里面相关推荐

  1. java for循环定义变量,在java语言里for循环里的变量如何声明在外面进行使用。

    在java语言里for循环里的变量如何声明在外面进行使用. 关注:142  答案:2  手机版 解决时间 2021-02-01 21:59 提问者懷念那年夏天 2021-01-31 21:11 pub ...

  2. c语言中在main外面定义的int变量,C语言中,把变量定义在主函数之外和定义在主函数之内有什么区别...

    C语言中,把变量定义在主函数之外和定义在主函数之内有什么区别 答案:7  信息版本:手机版 解决时间 2018-12-14 06:44 已解决 2018-12-13 14:23 C语言中,把变量定义在 ...

  3. java for循环 变量定义在内外_关于变量在for循环内外定义的思考

    在c#或java里面,我们通常会这样写for循环: for(int i = 0;i<10;i++){ Console.WriteLine(i);} 前一阵子,我突发奇想,如果按照下面这样写,会不 ...

  4. Java变量声明在循环体内还是循环体外,你用哪一个?

    作者 | java金融 来源 | java金融(ID:java4299) 头图 |  CSDN 下载自东方IC 引言 最近刷知乎的时候看到一个比较有意思的问题,变量声明在循环体内还是循环体外?这个问题 ...

  5. oracle存储过程、声明变量、for循环|转|

    oracle存储过程.声明变量.for循环 1.创建存储过程 create or replace procedure test(var_name_1 in type,var_name_2 out ty ...

  6. oracle存储过程、声明变量、for循环(转)

    oracle存储过程.声明变量.for循环 1.创建存储过程 create or replace procedure test(var_name_1 in type,var_name_2 out ty ...

  7. cmd变量,参数,for循环,

    cmd变量,参数,for循环, @echo off rem  ***************************************************** rem  Create By ...

  8. R语言 多个变量进行 卡方检验 循环 fisher检验 chi test 循环

    多变量循环卡方检验+检测理论频数+<1 进行fisher 单个卡方检验流程 table(data$smoke,data$sex) s=chisq.test(data$smoke,data$age ...

  9. Scala语法(一) 基础语法(变量常量判断循环数组集合)

    前言 在前面的章节中, 我们介绍了如何在Eclipse内安装Scala环境. 本章开始, 我们将讲解下Scala的基本语法. PS: 1. 个人虽然没有想转Scala语言开发的思想, 但是近来Scal ...

最新文章

  1. 数据结构之图的创建(邻接表)
  2. PHP机器学习库php-ml的简单测试和使用
  3. centos7离线安装bazel
  4. r语言clind函数_R 语言学习笔记 1
  5. SAP License:BCS进阶第五篇-BCS合并现金流量表的实现
  6. 在微软 Team 中查看 GIF 文件就能触发账户劫持漏洞?
  7. 【C#小知识】C#中一些易混淆概念总结(八)---------解析接口
  8. 安全使用Mac教程 – 使用文件保险箱加密 Mac 数据
  9. 全概率公式和贝叶斯公式的应用 (概统1)
  10. 顶岗实习周记java方向_java程序员的实习周记
  11. mysql中的事务和锁_MySQL中的事务和锁
  12. Day 3 Linux(目录篇 、文件操作篇 、压缩解压相关命令, 编辑器vi 、编译器gcc 、调试器gdb、 makefile工程管理器初学)
  13. 简单粗暴理解支持向量机(SVM)及其MATLAB实例
  14. shiro 权限框架
  15. java语言下列说法正确的是_中国大学MOOC: 以下关于Java语言说法正确的是( )。...
  16. Mysql和js试题_JS和MySQL常见问题
  17. php+转为文本,PHP将HTML转换成文本的实现代码
  18. bzoj3824[Usaco2014 Dec]Guard Mark 奶牛叠罗汉(II)
  19. 安防智能视频平台EasyCVR后台界面流量统计显示问题的优化
  20. 【线性代数】私人回顾

热门文章

  1. 软件工程导论11-软件测试
  2. 屁股坐久痛,用麻将当坐垫
  3. 完全二叉树叶子节点、度为1节点、度为2节点的个数
  4. 卡巴斯基杀毒软件的十九种实用使用方法
  5. 大数据Hadoop:杀鸡用的宰牛刀
  6. Sublime Text3中几款比较好看的主题
  7. Android java对接建行支付SDK
  8. oracle ogg端口,OGG报错 OGG-01223
  9. 谷歌浏览器自动定时刷新网页插件名称
  10. 第六章 项目进度管理