循环外和循环内定义变量的区别

一、代码展示

import java.util.HashMap;
import java.util.Map;

/**
 * @Package: raymond
 * @ClassName: Test
 * @Author: tanp
 * @Description: ${description}
 * @Date: 2020/8/10 14:12
 */
public class Test {

    public static void main(String[] args) {
        TestThread2 testThread = new TestThread2();
        testThread.start();
    }

    static class TestThread extends Thread {
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                Map<String,Object> map = new HashMap<>();
                map.put(i+"",i);
            }
        }
    }

    static class TestThread2 extends Thread {
        Map<String,Object> map;
        @Override
        public void run() {
            for(int i=0; i<10; i++){
                map = new HashMap<>();
                map.put(i+"",i);
            }
        }
    }
}

二、问题

从上面的代码可以看到,TestThread和TestThread2的区别在于map的定义是放在for循环外面还是里面,那么就有一个问题,在写代码的时候到底是要将变量定义在外面还是里面呢。

三、JVM运行时数据区

首先我们要知道JVM运行时数据区中有几大块,其中的两块分别为栈和堆

JVM

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址

堆(Heap

它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。

(1)       堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的

(2)       Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配

(3)       TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。

具体的jvm知识可以查看我的这篇博客https://blog.csdn.net/bird_tp/article/details/88560468

四、循环内和循环外定义变量的本质区别

结合上面的堆、栈信息,我们可以明白变量的定义是放在栈里面的,变量的实例化对象是放在堆里面的,所以我们前面两个线程中定义map的本质区别在于

线程TestThread在栈声明了10个栈内存地址,10个堆内存地址,而TestThread2只声明了1个栈内存地址,10个堆内存地址。TestThread2线程在循环实例化map时,只是通过一个栈内存地址移动引用指向了的10个堆内存地址。

总结起来就是
1、在循环外面的定义的变量,只在栈中声明了一次;
2、在循环里面的定义的变量,循环多少次就在栈中声明了多少次;

五、循环时具体如何定义变量

放在循环内部定义,确实会多次申请栈帧的内存空间,但其实话说回来,这样对性能的影响其实可以忽略不计,没什么大的问题。因为栈内存的分配非常之快,仅次于寄存器,所以,可以忽略不计。

总的来说,循环内的话,每次循环内部的局部变量在每次进for循环的时候都要重新定义一遍变量,也就是执行申请内存空间,变量压入堆栈的过程。
循环外定义的话,for循环一直用的是同一块内存空间,效率比较高,但是变量的作用域就大了,耗内存
所以,其实内外都可以的,总之就是空间和时间的权衡,看实际情况了,局部变量的数据类型、大小什么的都有关

下面粘贴下jdk7的hashmap的get方法,我们可以看到Object k就是定义在循环里面的。

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

六、总结

在for循环外面和里面定义变量,对于内存,性能影响其实没有什么多大区别。看个人使用情况而言,对于我个人使用而言,还是习惯定义在外面

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值