Java 垃圾收集器、字符串和字符串
因此,与使用StringBuilder相比,我在构建字符串所需的时间上有点胡闹,并且在垃圾收集器上也有点胡闹。作为CS一年级的学生,垃圾收集器对我来说也有点像魔术,它只是清理所有的东西并且“正常工作”。当我想到这个时,我有点困惑:Java 垃圾收集器、字符串和字符串,java,garbage-collection,Java,Garbage Collection,因此,与使用StringBuilder相比,我在构建字符串所需的时间上有点胡闹,并且在垃圾收集器上也有点胡闹。作为CS一年级的学生,垃圾收集器对我来说也有点像魔术,它只是清理所有的东西并且“正常工作”。当我想到这个时,我有点困惑: public class Main { public static void main(String[] args) { long time = System.currentTimeMillis(); new Test
public class Main
{
public static void main(String[] args)
{
long time = System.currentTimeMillis();
new Test();
for (int i= 0; i < 10000; i++)
{
String s = "a";
for (int c = 0; c < 26; c++)
{
s += (Character.toString((char) ('a' + c)));
//s += "testttzzz";
}
}
System.out.println(System.currentTimeMillis() - time);
}
}
class Test
{
@Override
protected void finalize() throws Throwable
{
System.out.println("FINALIZE TEST!");
}
}
公共类主
{
公共静态void main(字符串[]args)
{
长时间=System.currentTimeMillis();
新测试();
对于(int i=0;i<10000;i++)
{
字符串s=“a”;
对于(int c=0;c<26;c++)
{
s+=(Character.toString((char)('a'+c));
//s+=“testttzzz”;
}
}
System.out.println(System.currentTimeMillis()-time);
}
}
课堂测试
{
@凌驾
受保护的void finalize()抛出可丢弃的
{
System.out.println(“完成测试!”);
}
}
在上面的代码中,如果我取消注释掉行的+=“testttzzz”,垃圾收集器将被调用,它将输出FINALIZE TEST代码>。但是,如果该行被注释掉,垃圾收集器将不会在程序运行时运行,并且不会输出FINALIZE TEST代码>完全正确。为什么会这样
编辑:我尝试添加System.out.println(I)代码>在第一个for循环中,这样我就可以看到调用System.gc()的确切时间。添加该行似乎导致垃圾收集器不再运行。我真的很困惑
Edit2:如果有区别的话,我将使用JRE 1.7.0_45
并使用eclipse版本4.3.1来编译代码
Edit3:我猜额外代码行增加的时间似乎给了垃圾收集器更多的运行时间,并允许调用finalize()。不过很有趣
Edit4:根据Jon Skeet的说法,情况并非如此。垃圾收集器非常有趣如果没有注释掉的部分,您只使用了大约260 KB的有效负载内存。包括开销,您可能会获得高达1MB的可刮取数据
我运行了你的程序,并对照VisualVM检查了一下,看看发生了什么
VM以63.5MB的堆大小开始,因此它在需要分配新空间之前就拥有了该空间。
该程序一开始的内存使用量约为6.5MB,因此仅使用了大约10%的内存。在程序运行的过程中,内存使用量上升到了8.1MB,所以我给你一个,上升了1.6MB,但这仍然算不了什么。虚拟机还有很多空间。现在运行GC只会浪费CPU时间
我在程序的末尾添加了一个无限循环,以检查是否只是程序在GC启动之前停止了,但是不,不是,GC没有运行
我做的下一件事是取消这行的注释:
s += "testttzzz";
现在,内存使用量增加了一点点,但似乎刚刚足够让它超越“魔障”,GC运行起来
GC有一些指标决定它何时运行,这些指标在运行Java的VM之间有所不同。其中包括:
- 使用的堆内存百分比
- 已用内存的增长率
- 可以为堆分配的可用内存
- 当前CPU使用率
你说
“垃圾收集器对我来说也有点像魔术,它只是清理所有的东西并且“正常工作”
这就是它应该是什么样子。在Java中,GC的实现取决于创建VM的人。没有关于何时必须运行的标准。有方法System.gc(),但甚至没有强制gc运行,只是“暗示”现在是运行gc的好时机。
即使您在不同的系统上使用相同的VM,它的行为也可能完全不同。举个例子:我有一个Windows7 64位系统,带有4GB内存,运行一个32位Java虚拟机。我的默认最大堆大小是903.12 MB。我妻子有一个Windows 8 64位系统,4 GB RAM运行相同的32位Java虚拟机。她的默认最大堆大小只有247.5 MB!
这意味着,GC在我的系统上比在我妻子的系统上要懒得多
作为一名程序员,你可以信任GC来完成它的工作(清除内存,使你的程序有足够的内存),但不要让你的程序的任何部分依赖于GC以任何特定的方式执行,因为它不必也可能不会这样做。这是因为它不是确定性行为。垃圾收集器工作得很好,它可能不会在您期望的时候收集,所以除非您正在调优GC,否则您不应该在它上面花费太多时间。@Kayaman是的,我对GC一点也不了解。我只是觉得这是一件有趣的事情,也许这不仅仅是unpredictability@arshajii如果程序在GC运行之前结束,则不会。添加更多的代码会导致GC运行。@Kayaman是的,我想是这样。相信我,确实如此。如果程序正在退出,GC将不会费心运行。这就是为什么您不能相信正在运行的终结器。