我正在尝试编写一个对资源影响最小的代码,但我遇到了我不理解的GC行为。
显然,即使不再使用字符串,也不会立即从内存中清除字符串。
for(int i = 0; i < 999999999; i++)
System.out.println("Test");
根据图表我假设在每次循环运行时都会创建一个新的String对象,但是在下一次循环运行时它不会自动清除 - 如果是这种情况我想知道为什么会发生这种情况如果我误解了这种情况,我想知道“窗帘后面”究竟发生了什么。
当我将Sleep添加到上面提到的代码时,图表变得稳定,原因是什么?
for(int i = 0; i < 999999999; i++){
System.out.println("Test");
try{
Thread.sleep(1);
}
catch(Exception e){}
}
我也有一些关于特定案例的问题:
GC会被迫更积极吗?我的意思是缩短对象的生命周期而不是减少JVM分配的内存?
如果我将一个空值插入变量,它会影响GC清除之前的时间吗?
当我需要在其上运行大量正则表达式匹配时,使用字符串的正确方法是什么?
将String对象声明为“过时”的最佳方法是什么,以便GC清除它?
是否会出现上述情况,因为Java为字符串执行自动实习,如果有,有办法取消它吗?
非常感谢!
答案 0 :(得分:0)
垃圾收集器或多或少收集收集时间。
我可以解释基于CMS / ParNew的GC效果(因为我最了解这个组合),它的工作原理如下: 堆被分成两个区域(我现在不包括PermGen)。 老老少少 年轻人被分成'伊甸园'和'复制'(或幸存者) 当你生成一个新对象时,它会变成Young-&gt; Eden。在某些时候,伊甸园将达到其最大内存,然后将删除未使用的对象,仍然具有引用的对象将被复制到Young-&gt; Copy。
随着程序的不断运行,Young-&gt; Copy将达到最大内存。它将在另一个Young-&gt;复制存储空间中再次复制。
在某些时候,它不能再这样做了,所以有些对象会从Young-&gt; Copy复制到Old,这取决于复制计数器(我认为)。旧堆的故事也是如此。
那么你能调整什么?首先,您通常具有吞吐量(批处理)和低延迟(网页),ParNew / CMS组合用于低延迟。
由于我最了解ParNew / CMS,我将解释你可以考虑首先调整的内容:
然后还有更多。根据我的个人经验,对于大型应用程序,我们通常使用以下设置:
如果你真的想知道一切背后的东西,我建议你读一本书,因为真的,真的正在进行中。
答案 1 :(得分:0)
我假设在每次循环运行时都会创建一个新的String对象
不,如果它在每次迭代中创建一个新的String,你会得到更多的垃圾。
在这种垃圾率下,它可能是分配一些对象的分析器。
字符串文字是一次创建。 (在JVM中)
但在下一次循环运行时不会自动清除
正确,即使它是在每次迭代时创建的,GC只在需要时运行,在每次迭代时执行它都会非常昂贵。
当我将Sleep添加到上面提到的代码时,图形变得稳定,原因是什么?
你大大减慢了你的申请速度。
GC会被迫更积极吗?
您可以将Eden空间缩小,但这会降低您的应用程序速度。
如果我将一个空值插入变量,它会影响GC清除它的时间吗?
不,这很少有任何作用。
正则表达式创造了大量垃圾。如果您想减少分配并加快应用程序的速度,请避免使用正则表达式。当我需要在其上运行大量正则表达式匹配时,使用字符串的正确方法是什么
我最近通过直接字符串处理替换了一些常用的正则表达式,将应用程序加速了3倍。
声明String对象的最佳方法是什么?#34;过时&#34;那么GC会清除它吗?
在有限的范围内使用它。当范围结束时,对它的引用也可以是GCed。
上述情况是否会发生,因为Java会自动实习
一旦实例化了一个字符串,就不会重新创建它。
对于字符串,如果是,有没有办法取消它?
当然,每次都强制它创建一个新的String。这当然会产生更多的垃圾而且速度要慢得多(代码也会更长),但如果你愿意,你可以这样做。