zhaoritian19
V2EX  ›  Java

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

  •  
  •   zhaoritian19 · Dec 30, 2019 · 5473 views
    This topic created in 2348 days ago, the information mentioned may be changed or developed.

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

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

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

    除非有些引用没有被 gc,例如很简单的 ThreadLocal 中使用了 map,这种内存溢出的操作。
    LaughingCat
        13
    LaughingCat  
       Dec 31, 2019
    我以前也遇到过这种循环 new 溢出的问题,当在循环次数达到一定数量时,new 操作会在占用大量的内存空间,解决方式是在外面 new 一个对象,这个对象有处理数据的构造函数,然后在循环里面对该对象进行构造函数赋值就能达到你要的循环 new 的效果。
    rizon
        14
    rizon  
       Dec 31, 2019
    这事我也很纠结,正常来说,从代码的可读性来说,放到循环体内生命更合适,但是很多人又说处于性能考虑应该放到循环体外。
    我一般考虑可读性。 但是也是希望能得到一个更明确点的答案。
    至于内存泄漏问题,在 java 里是不存在的,搞 C 的才有这个问题。
    mightofcode
        15
    mightofcode  
       Jan 6, 2020
    贴代码比较好,看描述看不明白
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5699 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 80ms · UTC 03:22 · PVG 11:22 · LAX 20:22 · JFK 23:22
    ♥ Do have faith in what you're doing.