V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhaoritian19
V2EX  ›  Java

[ Java ] 变量声明在循环体内还是循环体外?

  •  
  •   zhaoritian19 · 2019-12-30 15:17:34 +08:00 · 4649 次点击
    这是一个创建于 1826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是一个已经被讨论了很久的问题了,能查到的答案各种都有,请问各位大佬们有什么高见?

    小白我现在项目中遇到了类似的问题,循环遍历一个对象集合,然后取其中的某些属性放入另一个对象集合中,目前是在循环的过程中 new 了新的对象,然后放入新的 list 中。在联调的时还在循环的时候日志打印了新的实体对象,但是却内存溢出项目挂掉了。   
    很费解,list 的大小也就 2000 多个对象,有那么费内存吗?为什么会内存溢出?是不是将变量的声明放在循环外会好一些?希望大佬们能帮忙答疑,谢谢
    
    15 条回复    2020-01-06 11:55:22 +08:00
    Esioner
        1
    Esioner  
       2019-12-30 15:35:51 +08:00
    list 存的是对象的引用把,如果你把变量声明放到外面会导致数据异常的问题把
    Arsenal16
        2
    Arsenal16  
       2019-12-30 15:39:58 +08:00 via Android
    list.stream().filter(你的过滤条件).map(你要映射的属性).collect(Collectors.toList());
    Java8 的话直接用这个吧。
    你那个又没代码,菜鸡如我,没法排查。
    Arsenal16
        3
    Arsenal16  
       2019-12-30 15:47:03 +08:00 via Android
    你这个应该放在循环体内创建对象,然后添加到 list
    cruii
        4
    cruii  
       2019-12-30 17:24:46 +08:00
    这样问问题就跟不贴图说自己电脑蓝屏了怎么解决一样
    matepi
        5
    matepi  
       2019-12-30 17:36:32 +08:00
    不会,循环体内变量实际会被优化提前到循环起始前
    和内存占用真正有关的是 new 动作
    要看你其他代码,包括 new 动作里面进一步的 new
    zhaoritian19
        6
    zhaoritian19  
    OP
       2019-12-30 17:59:53 +08:00
    @matepi 没有在 new 的实体对象里面进一步 new 别的对象,我也感觉单单是循环里面 new 实体对象不会导致内存溢出,而且才 1000 多个,GC 应该能处理的了。
    zhaoritian19
        7
    zhaoritian19  
    OP
       2019-12-30 18:01:14 +08:00
    @Arsenal16 老项目了用的 java7,没有升级到 java8。 如果是 8 就不会用循环来做了
    chendy
        8
    chendy  
       2019-12-30 18:14:17 +08:00
    内存溢出的话,用 -XX:+HeapDumpOnOutOfMemoryError 导出 dump,然后 mat 分析 dump 看是什么东西占用了太多内存
    2000 不多,但是也不知道每个对象多大,所以不好说…
    passerbytiny
        9
    passerbytiny  
       2019-12-30 18:16:27 +08:00
    变量声明应该放到循环体外(然并卵,减少的内存占用相对来说可以忽略),但给 list 的对象一定是在循环体内 new 出来的。

    list 上万都没问题,你这个能溢出应该是其他原因,需要根据 JVM 异常日志去定位。
    palmers
        10
    palmers  
       2019-12-30 19:39:03 +08:00
    得看看是堆内存还是栈内存 还有 同意 8#的同学把对应日志 dump 出来看看占用在哪里 问题原因应该就出来了
    choice4
        11
    choice4  
       2019-12-31 01:04:00 +08:00 via Android
    2000 个就溢出,,java 再费内存也没这么个费法啊
    nnnToTnnn
        12
    nnnToTnnn  
       2019-12-31 08:47:40 +08:00
    Java 无论是在循环体内还是循环体外,由于 java 特定的 gc 机制,就算你在循环体内声明了变量,也不可能内存溢出!!!

    除非有些引用没有被 gc,例如很简单的 ThreadLocal 中使用了 map,这种内存溢出的操作。
    LaughingCat
        13
    LaughingCat  
       2019-12-31 09:46:47 +08:00
    我以前也遇到过这种循环 new 溢出的问题,当在循环次数达到一定数量时,new 操作会在占用大量的内存空间,解决方式是在外面 new 一个对象,这个对象有处理数据的构造函数,然后在循环里面对该对象进行构造函数赋值就能达到你要的循环 new 的效果。
    rizon
        14
    rizon  
       2019-12-31 15:05:36 +08:00
    这事我也很纠结,正常来说,从代码的可读性来说,放到循环体内生命更合适,但是很多人又说处于性能考虑应该放到循环体外。
    我一般考虑可读性。 但是也是希望能得到一个更明确点的答案。
    至于内存泄漏问题,在 java 里是不存在的,搞 C 的才有这个问题。
    mightofcode
        15
    mightofcode  
       2020-01-06 11:55:22 +08:00
    贴代码比较好,看描述看不明白
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2799 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 12:43 · PVG 20:43 · LAX 04:43 · JFK 07:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.