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

时间:2017-08-30 15:56:20

标签: java memory gemfire

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

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缓存系统中。我需要优化应用程序以减少内存占用。

1 个答案:

答案 0 :(得分:2)

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

  

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

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

  RSS:20.0g   14.3克

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

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

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

<强>更新

  

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

确定

  

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

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

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

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

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

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

 jps -lvm
  

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

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

对于直接记忆,你可以试试sun.misc.SharedSecrets.getJavaNioAccess()。getDirectBufferPool()。getMemoryUsed()。

使用cmd,例如:

 jcmd <pid> VM.native_memory baseline

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

在linux中你也可以使用:

 pmap -x <pid>

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

  

请注意,我的应用程序运行在使用共享和复制缓存设置的对等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,那将非常有用。