为什么unix和Java RunTime显示的统计数据存在差异

我的应用程序存在一些内存问题,需要帮助理解这些统计信息。

Unix“top”为我的流程显示了这些统计数据 –

VSZ: 37.4g RSS: 20.0g 

因此,这意味着目前交换20g用于该过程和使用中。

但是,当我使用Runtime类从我的应用程序中打印统计信息时,我得到:

 Runtime.totalMemory() : 9.8G Runtime.freeMemory() : 3.6G Runtime.maxMemory() : 14.3G 

为什么[Runtime.totalMemory() – Runtime.freeMemory()]与RSS不匹配? 这是该进程当前使用的内存。 这两个数字之间存在巨大差异。

此外,运行时是否将未使用的内存(Runtime.freeMemory())返回给OS以供其他进程使用?

请注意,我的应用程序运行在使用共享和复制缓存设置的对等GemFire缓存系统中。 我需要优化应用程序以减少内存占用。

Runtime.totalMemory显示当前可用的内存。 Java懒惰地分配内存。

此外,运行时是否将未使用的内存(Runtime.freeMemory())返回给OS以供其他进程使用?

不。如果Java分配了内存(totalMemory),它现在就在java进程中。

RSS:20.0g 14.3G

如前所述,Java除了堆之外还使用内存。 Gemfire也使用了堆内存( 检查一下 )。 尝试在VisualVM-Buffer Monitor中查看它们。

您的基础设施(操作系统,虚拟机)是什么?

如果您不能使用标准工具,您可能应该使用JMX编写自己的可维护性代理( 例如 )

UPDATE

根据doc,默认情况下Gemfire使用JVM堆。

为什么RSS始终显示20G用于仅使用~10G堆内存的进程。

如果你仍然问,我会提供更多细节。 什么是java内存使用?

  • 堆内存( Xmx );
  • 堆栈内存(每个线程都有自己的堆栈ThreadStackSizeVMThreadStackSize );
  • MaxPermSize或MaxMetaspaceSize( MaxPermGenSizeMaxMetaspaceSize );
  • 直接字节缓冲区( MaxDirectMemorySize );
  • 内存池(Par Eden Space,Par Survivor Space,CMS Old Gen,Metaspace / PermGen,Code Cache,Compressed Class Space( CompressedClassSpaceSize ));
  • 字符串表(所有String.intern()将在其中, StringTableSize );
  • PerfDataMemorySize ;
  • MarkStackSize ;
  • CompilerThreadStackSize ;
  • 恒定池;
  • 我可能错过了什么 ;

要查看默认值,您可以运行:

  java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version 

要查看特定进程的哪些选项,您可以运行:

  jps -lvm 

unix中是否有命令行工具来确定其余用法?

对于其中一些是的。 对于他们中的一些没有。

对于直接内存,您可以尝试sun.misc.SharedSecrets.getJavaNioAccess()。getDirectBufferPool()。getMemoryUsed()。

使用cmd,例如:

  jcmd  VM.native_memory baseline 

但这取决于运行设置( NativeMemoryTracking )。 您可以在此处阅读如何启用本机内存跟踪。

在linux中你也可以使用:

  pmap -x  

总之,这可能无关紧要,因为你的任务:

请注意,我的应用程序运行在使用共享和复制缓存设置的对等GemFire缓存系统中。 我需要优化应用程序以减少内存占用。

而且你不能影响本机内存使用。 我想看看jmap util,它可以显示类直方图。 您应该检查GemFire中具有大尺寸的内容并查看这些对象,可能是您存储在缓存数据中,而不应该存在。 我的意思是在我的优化缓存实践中,我会查看对象和字段,看看哪些字段非常频繁,哪些字段不是。 另一种方法是检查序列化机制和对象布局。

正如我所提到的,您可以使用可维护性代理:

 import com.sun.tools.attach.VirtualMachine; import sun.tools.attach.HotSpotVirtualMachine; import java.io.InputStream; public class JMemoryMain { public static void main(String[] args) throws Exception { final int pid = JMemoryMainUtils.getPid(args); final HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine.attach(String.valueOf(pid)); final byte[] buffer = new byte[1024]; try (InputStream is = vm.heapHisto()) { for (int read; (read = is.read(buffer)) > 0;) { System.out.write(buffer, 0, read); } } vm.detach(); } } 

您需要JDK中的tools.jar依赖项来运行它。 它也可以打印你的类直方图,但有时候工作,当jmap没有。 此外,当您应该等待很多时间,在计算直方图时,您可以使用VM.getSystemDictionary()并仅查找您的类。 并且,如果由于开销而无法启用NMT,那将非常有用。