我有一个非常简单的类,它有一个整数变量。我只是将变量'i'的值打印到屏幕并递增它,并让线程休眠1秒钟。当我针对此方法运行探查器时,即使我没有创建任何新变量,内存使用量也会缓慢增加。执行此代码大约16个小时后,我发现内存使用量已增加到4 MB(当我启动程序时,最初为1 MB)。我是Java的新手。任何人都可以帮助解释我哪里出错,或者为什么即使没有创建新变量,内存使用量也会逐渐增加?提前致谢。
我正在使用netbeans 7.1及其分析器来查看内存使用情况。
public static void main(String[] args)
{
try
{
int i = 1;
while(true)
{
System.out.println(i);
i++;
Thread.sleep(1000);
}
}
catch(InterruptedException ex)
{
System.out.print(ex.toString());
}
}
程序启动时的初始内存使用情况:1569852字节。
执行循环16小时后的内存使用情况:4095829字节
答案 0 :(得分:2)
它不一定是内存泄漏。 GC运行时,将收集System.out.println(i);
语句中分配的对象(我假设)。 Java中的内存泄漏是当内存填满无法通过GC无法回收的无用对象时。
println(i)
正在使用Integer.toString(int)
将int
转换为字符串,并且每次都会分配一个新的String
。这不是泄漏,因为一旦将字符串复制到输出缓冲区,字符串将无法访问并成为GC的候选者。
其他可能的内存分配来源:
Thread.sleep可以分配对象。
某些私有JVM线程可能导致此问题。
探查器用于监视JVM状态的“java代理”代码可能导致此问题。它必须通过套接字将数据汇编并发送到探查器应用程序,这很可能涉及分配Java对象。它也可能在JVM的堆或非堆内存中累积内容。
但是,只要在运行GC的情况下可以回收空间,它就无所谓了。如果它不能,那么您可能在您正在使用的探查器中发现了JVM错误或错误。 (尝试用一个非常长的睡眠来替换循环并查看“泄漏”是否仍然存在。)如果这是由分析引起的缓慢泄漏可能无关紧要...因为您通常不运行生产代码启用了长时间的分析。
注意:不保证调用System.gc()
会导致GC运行。阅读javadoc。
答案 1 :(得分:1)
我在这段代码中没有看到任何内存泄漏。您应该看到Java中的垃圾收集器是如何工作的以及它的策略。基本上讲GC在需要之前不会清理 - 如特定策略所示。
您也可以尝试拨打System.gc()
。
可能在两个Java Core函数中创建对象。
答案 2 :(得分:0)
这是由于控制台中显示的文本和整数的大小(一点点)。
Java打印功能使用8位ASCII,因此有56000个数字打印,每个字符8个字节很快就会占用内存。
答案 3 :(得分:0)
按照本教程查找内存泄漏:Analyzing Memory Leak in Java Applications using VisualVM。您必须在开始时制作应用程序的快照,并在一段时间后制作另一个应用程序。使用VisualVM,您可以执行此操作并将这些快照与快照进行比较。
答案 4 :(得分:0)
尝试将JVM上限内存设置得太低,以致可能的泄漏会导致内存不足。
如果使用的内存达到了这个限制并继续快乐地工作,那么垃圾收集正在发挥作用。
如果反而炸弹,那么你就有了一个真正的问题......
答案 5 :(得分:0)
这似乎没有泄漏,因为剖析器的图表也说明了这一点。在某些间隔之后,即当执行GC时,图形急剧下降。如果图表稳定攀升,那将是一次泄漏。之后剩余的堆空间必须由thread.sleep()使用,并且也可以使用探测器的某些代码(如上面的一个答案中所述)。
您可以尝试运行位于%JAVA_HOME%/bin
的VisualVM并在其中分析您的应用程序。它还为您提供了随意执行GC的选项以及更多选项。
我注意到我使用了更多内存的VisualVM的更多功能(高达10MB)。所以这个增加,它必须来自你的探查器,但它仍然不是泄漏,因为GC上的空间被回收。
答案 6 :(得分:-1)
没有printlns会发生这种情况吗?换句话说,也许保持打印机显示在控制台上就是消耗内存。