我改进了代码,以使垃圾收集器获得更好的结果。
现在,当我致电System.gc()
时,它会释放所有内存。但是,当我在不调用System.gc()
的情况下查看内存使用情况时,该应用程序确实会保留并使用越来越多的内存。
这是否意味着我的改进正在起作用,并且我所有的引用都正确,并且我可以忽略JVM如何自行释放内存。还是我的代码中还有另一个问题,这就是JVM确实保留了更多内存而不运行垃圾回收器的原因。
答案 0 :(得分:2)
取决于您的JVM使用哪个GC。 如果是JDK9,则在内存消耗方面可能是“贪婪”的G1, 因此,根据您检查内存使用情况的方式,它可能看起来好像占用了大量内存(在此情况下,这是保留它并动态/按需使用/释放)。
您可以使用
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
检查内存消耗。
对于GC和内存消耗分析,请查看以下内容: High memory usage issues with G1 Garbage collector + https://www.javacodegeeks.com/2017/11/minimize-java-memory-usage-right-garbage-collector.html
答案 1 :(得分:2)
未使用的内存是浪费的内存。
为什么要显式调用JSON.parse(obj);
。恕我直言,您永远不应调用它,并将其留给JVM决定何时运行GC。 (如果您是新手,JVM会比您做出更好的决定。仅当您真正知道自己在做什么时才调用System.gc()
。)通常,bad practice是调用System.gc()
的地方。
System.gc()
只是对JVM的运行GC的请求/提示。这绝不意味着肯定可以运行GC。
您可能会在Java中发生内存泄漏,但这肯定不是您要解决的问题,因为正如您在调用System.gc()
时提到的那样,您会看到释放了一些内存。 (因此,不是仍然保留未使用对象的引用,这可能会阻止GC清理这些对象。)
为什么您认为自己的代码有问题?在某些情况下,可能不需要更多内存,或者如果需要内存,那么您已经有足够的内存了(用通俗易懂的话来说,GC不会释放内存,因为程序仍有很多运行空间-那么为什么GC还要清理内存呢?)。
答案 2 :(得分:1)
无法强制JVM释放内存,System.gc()
只是一个提示。由GC来管理内存(请注意有各种类型的内存,例如堆,元空间,堆外)。每个GC算法都有多个可调整的配置参数,但都不会为您提供按需释放内存的选项。
JVM在启动时会保留内存,并从操作系统请求其他内存,直到达到配置的任何限制。它以块为单位递增,一次请求MB或更多的内存,因为从OS逐字节地请求内存效率很低。
答案 3 :(得分:0)
当然,您可能会发生内存泄漏,这意味着您的程序会在不释放内存的情况下继续分配内存。 (例如,在数量不断增长的列表或地图中。)您将需要一个内存探查器,以确保您不会遇到这种情况。
除此之外,如果虚拟机似乎一直在分配内存而不释放它,我不会担心。这就是现代VM的工作方式,尤其是在“客户端”模式下:只要有足够的可用内存,它们就不会浪费时间进行垃圾回收。如果达到内存限制,那么垃圾收集器就会启动。 (“客户端”与“服务器”模式是一个JVM参数,您可以根据需要进行试验,更多信息请参见Real differences between "java -server" and "java -client"?)
除此之外,您可以做的是:
a)确保执行完整GC的机制实际上在执行完整GC。我知道的最好的机制(虽然不能保证一定能正常工作,但据我所知它似乎可以正常工作)是分配仅通过软引用引用的对象,然后继续调用GC直到软引用变为null
b)(例如,如果启用了断言)在调试运行时,每隔几秒钟就会在单独的线程上触发一次完整的GC。然后,如果查看VM占用的内存,则该内存应大致保持不变。如果没有,则存在内存泄漏。