Java高内存使用率 - GC字符串

时间:2016-12-08 11:45:45

标签: java string memory garbage-collection jvm

我正在尝试编写一个对资源影响最小的代码,但我遇到了我不理解的GC行为。

  1. 显然,即使不再使用字符串,也不会立即从内存中清除字符串。

    for(int i = 0; i < 999999999; i++)
        System.out.println("Test");
    
  2. Memory usage graph

    根据图表我假设在每次循环运行时都会创建一个新的String对象,但是在下一次循环运行时它不会自动清除 - 如果是这种情况我想知道为什么会发生这种情况如果我误解了这种情况,我想知道“窗帘后面”究竟发生了什么。

    1. 当我将Sleep添加到上面提到的代码时,图表变得稳定,原因是什么?

      for(int i = 0; i < 999999999; i++){
      
          System.out.println("Test");
      
          try{
              Thread.sleep(1);
          }
          catch(Exception e){}
      }
      
    2. Stable graph

      我也有一些关于特定案例的问题:

      • GC会被迫更积极吗?我的意思是缩短对象的生命周期而不是减少JVM分配的内存?

      • 如果我将一个空值插入变量,它会影响GC清除之前的时间吗?

      • 当我需要在其上运行大量正则表达式匹配时,使用字符串的正确方法是什么?

      • 将String对象声明为“过时”的最佳方法是什么,以便GC清除它?

      • 是否会出现上述情况,因为Java为字符串执行自动实习,如果有,有办法取消它吗?

      非常感谢!

2 个答案:

答案 0 :(得分:0)

垃圾收集器或多或少收集收集时间。

  • 是的,取决于您使用的收藏家。你可以设置几十个vm属性,其中一些属性相互影响。
  • 我认为它不适用于'较新'的JDK
  • 通常你不在乎。对于GC来说,更多的是不要将大量的数据加载到你的内存中。关于字符串的一个特点是它的实习生,但字符串也会像其他对象一样gc'd。
  • 当没有对字符串/实习生的引用时(退出大括号时)
  • 不,情况确实发生了,因为java的GC以这种方式工作......

我可以解释基于CMS / ParNew的GC效果(因为我最了解这个组合),它的工作原理如下: 堆被分成两个区域(我现在不包括PermGen)。 老老少少 年轻人被分成'伊甸园'和'复制'(或幸存者) 当你生成一个新对象时,它会变成Young-&gt; Eden。在某些时候,伊甸园将达到其最大内存,然后将删除未使用的对象,仍然具有引用的对象将被复制到Young-&gt; Copy。

随着程序的不断运行,Young-&gt; Copy将达到最大内存。它将在另一个Young-&gt;复制存储空间中再次复制。

在某些时候,它不能再这样做了,所以有些对象会从Young-&gt; Copy复制到Old,这取决于复制计数器(我认为)。旧堆的故事也是如此。

那么你能调整什么?首先,您通常具有吞吐量(批处理)和低延迟(网页),ParNew / CMS组合用于低延迟。

由于我最了解ParNew / CMS,我将解释你可以考虑首先调整的内容:

  • 你可以调整最大内存(更多的内存意味着更多的管理,应用程序需要运行的内存越少,一般情况下越好)
  • 您可以调整年轻人和老年人之间的堆积比例
  • 您可以调整年轻时的伊甸园和副本之间的比率
  • 您可以调整CMS开始其收集周期的时间

然后还有更多。根据我的个人经验,对于大型应用程序,我们通常使用以下设置:

  • 将最小和最大内存修复为相同大小(不更改最大堆)
  • 新比例约1:4到1:7
  • 禁用System.gc()
  • 记录很多gc的东西
  • 在OutOfMemory上发出提醒
  • 对日志进行每周分析并确定调整参数。 (一次只有一个参数;)

如果你真的想知道一切背后的东西,我建议你读一本书,因为真的,真的正在进行中。

答案 1 :(得分:0)

  

我假设在每次循环运行时都会创建一个新的String对象

不,如果它在每次迭代中创建一个新的String,你会得到更多的垃圾。

在这种垃圾率下,它可能是分配一些对象的分析器。

字符串文字是一次创建。 (在JVM中)

  

但在下一次循环运行时不会自动清除

正确,即使它是在每次迭代时创建的,GC只在需要时运行,在每次迭代时执行它都会非常昂贵。

  

当我将Sleep添加到上面提到的代码时,图形变得稳定,原因是什么?

你大大减慢了你的申请速度。

  

GC会被迫更积极吗?

您可以将Eden空间缩小,但这会降低您的应用程序速度。

  

如果我将一个空值插入变量,它会影响GC清除它的时间吗?

不,这很少有任何作用。

  

当我需要在其上运行大量正则表达式匹配时,使用字符串的正确方法是什么

正则表达式创造了大量垃圾。如果您想减少分配并加快应用程序的速度,请避免使用正则表达式。

我最近通过直接字符串处理替换了一些常用的正则表达式,将应用程序加速了3倍。

  

声明String对象的最佳方法是什么?#34;过时&#34;那么GC会清除它吗?

在有限的范围内使用它。当范围结束时,对它的引用也可以是GCed。

  

上述情况是否会发生,因为Java会自动实习

一旦实例化了一个字符串,就不会重新创建它。

  

对于字符串,如果是,有没有办法取消它?

当然,每次都强制它创建一个新的String。这当然会产生更多的垃圾而且速度要慢得多(代码也会更长),但如果你愿意,你可以这样做。