当前位置: 首页 > 知识库问答 >
问题:

监视JVM的非堆内存使用情况

昌学
2023-03-14

我们通常处理OutOfMemoryError问题是因为堆或permgen大小配置问题。

但所有JVM内存都不是permgen或heap。据我理解,它还可以与线程/堆栈、原生JVM代码...

但是使用pmap我可以看到进程分配了9.3G,这是3.3G的离堆内存使用量。

我想知道有什么可能性来监视和调优这种额外的离堆内存消耗。

我不使用直接离堆内存访问(MaxDirectMemorySize是64M默认值)

Context: Load testing
Application: Solr/Lucene server
OS: Ubuntu
Thread count: 700
Virtualization: vSphere (run by us, no external hosting)

JVM

java version "1.7.0_09"
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)

调谐

-Xms=6g
-Xms=6g
-XX:MaxPermSize=128m

-XX:-UseGCOverheadLimit
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSClassUnloadingEnabled

-XX:+OptimizeStringConcat
-XX:+UseCompressedStrings 
-XX:+UseStringCache 

内存映射:

https://gist.github.com/slorber/5629214

vmstat

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 1  0   1743    381      4   1150    1    1    60    92    2    0  1  0 99  0

免费

             total       used       free     shared    buffers     cached
Mem:          7986       7605        381          0          4       1150
-/+ buffers/cache:       6449       1536
Swap:         4091       1743       2348

顶部

top - 11:15:49 up 42 days,  1:34,  2 users,  load average: 1.44, 2.11, 2.46
Tasks: 104 total,   1 running, 103 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.5%us,  0.2%sy,  0.0%ni, 98.9%id,  0.4%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   8178412k total,  7773356k used,   405056k free,     4200k buffers
Swap:  4190204k total,  1796368k used,  2393836k free,  1179380k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                                 
17833 jmxtrans  20   0 2458m 145m 2488 S    1  1.8 206:56.06 java                                                                                                                                    
 1237 logstash  20   0 2503m 142m 2468 S    1  1.8 354:23.19 java                                                                                                                                    
11348 tomcat    20   0 9184m 5.6g 2808 S    1 71.3 642:25.41 java                                                                                                                                    
    1 root      20   0 24324 1188  656 S    0  0.0   0:01.52 init                                                                                                                                    
    2 root      20   0     0    0    0 S    0  0.0   0:00.26 kthreadd             
...

df->tmpfs

Filesystem                1K-blocks     Used Available Use% Mounted on
tmpfs                       1635684      272   1635412   1% /run

我们面临的主要问题是:

  • 服务器有8G物理内存
  • Solr堆只需要6G
  • 有1.5g交换
  • swappiness=0
  • 堆消耗似乎已适当调整
  • 在服务器上运行:仅Solr和一些监视内容
  • 我们有正确的平均响应时间
  • 我们有时会出现反常的长暂停,最长可达20秒

我猜暂停可能是交换堆上的GC满了,对吧?

为什么会有这么多掉期?

我甚至不知道这是使服务器交换的JVM还是我看不到的隐藏的东西。可能是操作系统页面缓存?但不确定如果创建了交换,操作系统为什么会创建页面缓存条目。

我正在考虑测试一些流行的基于Java的存储/NoSQL(如ElasticSearch、Voldemort或Cassandra)中使用的mlockall技巧:检查Make jvm/solr not swap,using mlockall

编辑:

在这里可以看到max heap、used heap(蓝色)、used swap(红色)。好像有点关联。

我可以看到石墨中有许多次新的GC有规律地发生。并且有几个CMS GC对应于图片的堆显着减少。

停顿似乎与堆的减少并不相关,而是有规律地分布在10:00到11:30之间,所以我猜它可能与ParNew GC有关。

在负载测试期间,我可以看到一些磁盘activity,也可以看到一些交换IO activity,当测试结束时,这真的很平静。

共有1个答案

裴学
2023-03-14

您的堆实际上使用了6.5GB的虚拟内存(这可能包括perm gen)

您有一堆使用64 MB堆栈的线程。不清楚为什么有些是,而另一些是使用默认的1 MB。

总共有930万KB的虚拟内存。我只会担心居民的规模。

尝试使用top查找进程的驻留大小。

你可能会发现这个程序很有用

    BufferedReader br = new BufferedReader(new FileReader("C:/dev/gistfile1.txt"));
    long total = 0;
    for(String line; (line = br.readLine())!= null;) {
        String[] parts = line.split("[- ]");
        long start = new BigInteger(parts[0], 16).longValue();
        long end = new BigInteger(parts[1], 16).longValue();
        long size = end - start + 1;
        if (size > 1000000)
            System.out.printf("%,d : %s%n", size, line);
        total += size;
    }
    System.out.println("total: " + total/1024);

除非您有一个使用内存的JNI库,否则我猜您有很多线程,每个线程都有自己的堆栈空间。我会检查你有多少线程。您可以减少每个线程的最大堆栈空间,但更好的选择可能是减少您拥有的线程数。

根据定义,关闭堆内存是非托管的,因此不容易对其进行“调优”。甚至调优堆也不简单。

64位JVM上的默认堆栈大小是1024K,因此700个线程将使用700 MB的虚拟内存。

您不应该混淆虚拟内存大小和驻留内存大小。64位应用程序上的虚拟内存几乎是免费的,它只是您应该担心的常驻内存大小。

在我看来,你总共有9.3GB。

  • 6.0 GB堆。
  • 128 MB烫发GEN
  • 700 MB堆栈。
  • <250共享库
  • 2.2 GB未知(我怀疑虚拟内存不是驻留内存)

上次有人遇到这个问题时,他们的线程比他们想象的要多得多。我将检查您拥有的最大线程数,因为它是决定虚拟大小的峰值。接近3000点了吗?

嗯,每一对都是一根线。

7f0cffddf000-7f0cffedd000 rw-p 00000000 00:00 0 
7f0cffedd000-7f0cffee0000 ---p 00000000 00:00 0

而这些说明你现在的线程略少于700个.....

 类似资料:
  • 问题内容: jvm进程的内存使用量一直在增加,并且从未减少。我通过在linux服务器上执行top进行检查。该应用程序正在将作业调度到群集(使用Quartz + SunJava DRMAA API) Java堆空间在应用程序生命周期内保持在限制之内,但是jvm进程显示内存使用率稳定增长且从未下降。 这是内存泄漏吗?如果是这样,为什么堆空间在限制之内。有人可以解释一下。 更新: 当我通过jconsol

  • 问题内容: 我目前正在测试将密钥插入数据库Redis(在本地)中。我有超过500万个密钥,而且我只有4GB的RAM,所以一时我达到了RAM的容量并交换了数据(并且我的PC掉了)。 我的问题是:如何在具有Redis数据库的计算机上监视内存使用情况,并以此方式发出警报,不再在Redis数据库中插入某些密钥? 谢谢。 问题答案: 关于内存使用情况,建议您查看redis.io 常见问题解答以及有关将red

  • vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写,可实时动态监视操作系统的虚拟内存、进程、CPU活动。 10.1. vmstat的语法   vmstat [-V] [-n] [delay [count]] - -V表示打印出版本信息;- -n表示在周期性循环输出时,输出的头部信息仅显示一次;- delay是两次输出之间的延迟时间;- count是指按照这个时

  • 问题内容: 如何监视Node.js的内存使用情况? 问题答案: node-memwatch:检测并查找Node.JS代码中的内存泄漏。查看本教程,以跟踪Node.js中的内存泄漏

  • 如何监视Node.js的内存使用情况?

  • 本文向大家介绍详解JVM 运行时内存使用情况监控,包括了详解JVM 运行时内存使用情况监控的使用技巧和注意事项,需要的朋友参考一下 java 语言, 开发者不能直接控制程序运行内存, 对象的创建都是由类加载器一步步解析, 执行与生成与内存区域中的; 并且jvm有自己的垃圾回收器对内存区域管理, 回收; 但是我们已经可以通过一些工具来在程序运行时查看对应的jvm内存使用情况, 帮助更好的分析与优化我