简体   繁体   English

垃圾收集器,字符串和终结混乱

[英]Garbage Collector, Strings, and Finalize confusion

So I was fooling around a little bit with the amount of time it takes to build Strings vs using StringBuilder and was also messing around a little with the garbage collector. 因此,我花了一些时间来构建String和vs使用StringBuilder花费了很多时间,并且还浪费了一些垃圾回收器。 For me as a first year CS student, the garbage collector is a little bit like magic too me where it just cleans up everything and "just works". 对于我作为CS一年级学生来说,垃圾收集器也有点像魔术,它可以清理一切并“正常工作”。 I was a little confused when I came up with this: 当我想到这个时,我有点困惑:

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!");
    }
}

Inside the code above, if I uncomment out the line 's += "testttzzz" the garbage collector will be called and it will output FINALIZE TEST! 在上面的代码中,如果我取消注释该行的+ =“ testttzzz”,则将调用垃圾收集器,并将输出FINALIZE TEST! . However, if that line is commented out the garbage collector will not run while the program is running and wont output FINALIZE TEST! 但是,如果将该行注释掉,则程序运行时垃圾收集器将不会运行,并且不会输出FINALIZE TEST! at all. 完全没有 Why is this? 为什么是这样?

Edit: I tried adding System.out.println(i); 编辑:我试图添加System.out.println(i); inside the first for loop so I can see when exactly System.gc() is being called. 在第一个for循环中,这样我可以看到何时准确调用System.gc()。 It seems that adding that line caused the garbage collector to not be ran at all anymore. 似乎添加该行导致垃圾收集器不再运行。 I am really confused. 我真的很困惑。

Edit2: If it makes a difference, I am using JRE 1.7.0_45 and using eclipse version 4.3.1 to compile the code Edit2:如果有所不同,我正在使用JRE 1.7.0_45并使用Eclipse版本4.3.1编译代码

Edit3: I guess it just appears that the added time from the extra lines of code gives the garbage collector more time to run and allows finalize() to be called. Edit3:我想似乎只是多余的代码行增加了时间,使垃圾回收器有更多的运行时间,并允许调用finalize()。 Interesting nevertheless. 有趣的是。

Edit4: Well, according to Jon Skeet that is not the case. Edit4:恩,据乔恩·斯凯特说,事实并非如此。 The garbage collector is pretty interesting 垃圾收集器很有趣

Without the commented-out part you are only using about 260 KB payload memory. 没有注释掉的部分,您仅使用大约260 KB的有效负载内存。 Including overhead you might get up to 1 MB scrapable data. 包括开销,您可能最多获得1 MB的可抓取数据。

I ran your program and checked it against VisualVM to see what is happening. 我运行了您的程序,并针对VisualVM进行了检查,以查看发生了什么情况。

The VM starts with a heap size of 63.5 MB, so it has that space before it would need to allocate new space. VM开始时的堆大小为63.5 MB,因此在需要分配新空间之前,它具有该空间。 The program starts with a memory usage of about 6.5 MB, so just about 10% of the memory it has is used. 该程序以大约6.5 MB的内存使用开始,因此仅使用了其已用内存的10%。 During the course of the program the memory usage goes up to 8.1 MB, so I give you that, it was 1.6 MB up, but still, that is nothing. 在程序执行过程中,内存使用量高达8.1 MB,所以我给您提供了1.6 MB的信息,但是,那仍然是什么。 The VM has tons of space left. 虚拟机还剩下很多空间。 Running the GC now would be just a waste of CPU time. 现在运行GC只会浪费CPU时间。

I added an infinite loop at the end of the program to check if it's just that the program went down before the GC could kick in, but no, it wasn't, the GC did not run. 我在程序末尾添加了一个无限循环,以检查是否只是该程序在GC可以启动之前就关闭了,但是不,不是,GC没有运行。

Next thing I did was uncommenting this line: 我要做的下一件事是取消注释此行:

s += "testttzzz";

Now the memory usage went up just a tiny bit more, but seemingly just enough to make it above the "magic barrier" and the GC ran. 现在,内存使用量仅增加了一点点,但似乎足以使其超出“魔术屏障”,GC得以运行。

The GC has a few metrics that decide when it runs and those differ from one VM running Java to another. GC具有一些度量标准,这些度量标准决定何时运行,以及从一个运行Java的VM到另一个运行Java的VM的不同。 Some of them are: 他们之中有一些是:

  • Percentage of heap memory used 已使用堆内存的百分比
  • Growth rate of used memory 已用内存的增长率
  • Free memory that can be allocated for the heap 可以为堆分配的可用内存
  • Current CPU usage 当前CPU使用率

You said 你说

"the garbage collector is a little bit like magic too me where it just cleans up everything and "just works"." “在我看来,垃圾收集器也有点像魔术,它可以清理一切并“正常工作”。”

And that is just about how it should be. 那就是应该的样子。 In Java the implementation of the GC is up to the person who created the VM. 在Java中,GC的实现取决于创建VM的人员。 There is no standard about when it has to run. 没有关于何时运行的标准。 There is the method System.gc(), but not even that one forces the GC to run, but merely "suggests" that now would be a good time to run the GC. 有方法System.gc(),但是甚至没有人强迫GC运行,而仅仅是“建议”,这将是运行GC的好时机。 Even if you use the same VM on a different system it can act completely different. 即使您在不同系统上使用相同的VM,它的行为也可能完全不同。 As an example: I've got an Windows 7 64-Bit system with 4 GB RAM running an 32-Bit Java VM. 举个例子:我有一个Windows 7 64位系统,带有4 GB RAM,运行32位Java VM。 My default maximum heap size is 903.12 MB. 我的默认最大堆大小为903.12 MB。 My wife has an Windows 8 64-Bit system with 4 GB RAM running the same 32-Bit Java VM. 我的妻子有一个Windows 8 64位系统,其中4 GB RAM运行同一32位Java VM。 Her default maximum heap size is only 247.5 MB! 她的默认最大堆大小仅为247.5 MB! This means, the GC would be a lot lazier on my system than on my wife's. 这意味着,GC在我的系统上比我妻子的系统更懒惰。

As a programmer you can trust the GC to do it's job (clear up memory so you have enough memory for your program) but do not make any parts of your program depend on the GC performing in any certain way, because it doesn't have to and it probably will not. 作为程序员,您可以信任GC来完成其工作(清理内存,以便为程序留出足够的内存),但不要让程序的任何部分依赖于GC以某种特定方式执行,因为它没有到它可能不会。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM