有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java XX:NativeMemoryTracking未从_java_选项中获取

我无法通过_JAVA_OPTIONS获取NMT设置。我的环境是kubernetes集群上的一个Docker容器,其中_JAVA_OPTIONS包含一个启用NMT的标志(见下文)

为了演示,我创建了一个小演示类Hello,它每秒打印一行

a)我在没有命令行参数的情况下运行Hello

[root@ticc-services-abo-3354894200-5fixb tmp]# echo $_JAVA_OPTIONS
-Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
[root@ticc-services-abo-3354894200-5fixb tmp]# java Hello
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
hello 0
hello 1
...

在另一台控制台上,我试图获取NTM摘要,但无法访问:

[root@ticc-services-abo-3354894200-5fixb /]# jcmd
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
1 /opt/abo.jar
740 Hello
766 sun.tools.jcmd.JCmd
[root@ticc-services-abo-3354894200-5fixb /]# jcmd 740 VM.native_memory
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
740:
Native memory tracking is not enabled

b)现在我直接在命令行上设置NMT标志:

[root@ticc-services-abo-3354894200-5fixb tmp]# java -XX:NativeMemoryTracking=summary Hello
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
hello 0
hello 1
...

NMT的工作原理是:

[root@ticc-services-abo-3354894200-5fixb tmp]# jcmd
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
1 /opt/abo.jar
834 Hello
846 sun.tools.jcmd.JCmd
[root@ticc-services-abo-3354894200-5fixb tmp]# jcmd 834 VM.native_memory summary
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
834:

Native Memory Tracking:

Total: reserved=1873866KB, committed=574898KB
-                 Java Heap (reserved=524288KB, committed=524288KB)
                        (mmap: reserved=524288KB, committed=524288KB)
...

在修改Hello以打印其堆总数和最大值后,我们看到-Xms-Xmx被拾取,但NMT标志没有,因为Java没有抱怨错误的NMT标志:

[root@ticc-services-abo-3354894200-5fixb tmp]# echo $_JAVA_OPTIONS
-Xmx256m -Xms128m -XX:NativeMemoryTracking=summary_FOO
[root@ticc-services-abo-3354894200-5fixb tmp]# java Hello
Picked up _JAVA_OPTIONS: -Xmx256m -Xms128m  -XX:NativeMemoryTracking=summary_FOO
heap: total=128974848, max=239075328
hello 0
hello 1
hello 2

以下是我的环境:

[root@ticc-services-abo-3354894200-5fixb /]# uname -a
Linux ticc-services-abo-3354894200-5fixb 4.7.3-coreos-r2 #1 SMP Tue Nov 1 01:38:43 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
[root@ticc-services-abo-3354894200-5fixb /]# java -version
Picked up _JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

这看起来很奇怪,所以任何提示或想法都是非常欢迎的


共 (1) 个答案

  1. # 1 楼答案

    我确实认为,机器中存在的环境变量和启动这个Java进程的VM参数之间存在混淆

    你可以叫它\u JAVA\u OPTIONS、JAVA\u OPTIONS、MY\u STARTUP\u OPTION或任何其他名称,这个名称没有什么特别之处,它不是JAVA进程的保留字

    Java代码打印出该变量的值,这一事实也不会让它变得特别:

      System.out.println("Picked up JAVA_OPTIONS: "+System.getenv("_JAVA_OPTIONS"));
      System.out.println("Picked up JAVA_OPTIONS: "+System.getenv("JAVA_OPTIONS"));
    

    对于这个Java进程,它只是另一个常见的env变量。 这里重要的是知道这个变量是否用于启动流程,根据本例中显示的步骤顺序,答案是否定的

    如果希望使该变量用于启动该Java进程,则应使用:

    java $JAVA_OPTIONS Hello
    

    或者

    java $_JAVA_OPTIONS Hello
    

    此外,要打印此Java进程的VM参数,可以使用:

    ManagementFactory.getRuntimeMXBean().getInputArguments();
    

    下面是完整的Java代码

    import java.lang.management.ManagementFactory;
    import java.util.List;
    
    public class Hello {
    
        public static void main(String[] args) {
            int i = 0;
            System.out.println("Picked up JAVA_OPTIONS: "+System.getenv("JAVA_OPTIONS"));
            System.out.println("VMArguments: "+Hello.vmArguments().toString());
            try {
    
                while (true) {
                    System.out.println("hello " + (i++));
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                System.out.println("Good bye");
                e.printStackTrace();
            }
    
        }
    
        static List<String> vmArguments() {
            return ManagementFactory.getRuntimeMXBean().getInputArguments();
          }
    
    }
    

    还有一个执行的例子:

    C:\Hello\bin>echo %JAVA_OPTIONS%
    -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
    
    C:\Hello\bin>echo %MY_STARTUP_OPTION%
    -XX:NativeMemoryTracking=detail
    
    C:\Hello\bin>java %MY_STARTUP_OPTION% Hello
    Picked up JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
    VMArguments: [-XX:NativeMemoryTracking=detail]
    hello 0
    
    C:\Hello\bin>java %JAVA_OPTIONS% Hello
    Picked up JAVA_OPTIONS: -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
    VMArguments: [-Xmx512m, -Xms512m, -XX:NativeMemoryTracking=summary]
    hello 0
    

    在另一个终端上,您可以使用$JAVA_HOME/bin/jpsps-fea | grep JAVA。 以下是Windows中的一个示例:

    C:\Users\MyUser>jps -lv
    5644 Hello -Xmx512m -Xms512m -XX:NativeMemoryTracking=summary
    

    我希望名为JAVA_OPTIONS的变量或任何env变量与VM参数之间的区别是明确的

    回到你最初的问题,我不完全确定,但是Kubernetes似乎使用了JAVA_OPTS环境变量。勾选https://dev.to/sandrogiacom/kubernetes-for-java-developers-debug-application-4l1a

    关于NMT的选项,官方文件提到了“摘要”和“细节”

    参考:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html

    希望有帮助