jvm内存 大于 xmx

“嘿,你能来看看奇怪的东西吗?” 这就是我开始研究支持案例的方式,将我引向了这篇博客文章。 眼前的具体问题与报告可用内存数量不同的不同工具有关。

简而言之,一位工程师正在研究特定应用程序的过多内存使用情况,据他所知,该应用程序可以使用2G的堆。 但是无论出于什么原因,JVM工具本身似乎都没有决定该进程真正拥有多少内存。 例如, jconsole猜测总可用堆等于1,963M,而jvisualvm声称其等于2,048M。 那么哪个工具是正确的,为什么另一个却显示不同的信息呢?

确实确实很奇怪,尤其是看到通常的可疑对象都被淘汰了– JVM并没有采取任何明显的技巧,例如:

  • -Xmx-Xms相等,因此在运行时堆增加期间报告的数字不会更改
  • 通过关闭自适应大小调整策略( -XX:-UseAdaptiveSizePolicy ),防止JVM动态调整内存池的大小

重现差异

理解问题的第一步是放大工具实现。 通过标准API访问可用的内存信息非常简单,如下所示:

System.out.println("Runtime.getRuntime().maxMemory()="+Runtime.getRuntime().maxMemory());

确实,这就是手头工具似乎正在使用的工具。 回答此类问题的第一步是拥有可重现的测试用例。 为此,我编写了以下代码段:

package eu.plumbr.test;
//imports skipped for brevitypublic class HeapSizeDifferences {static Collection<Object> objects = new ArrayList<Object>();static long lastMaxMemory = 0;public static void main(String[] args) {try {List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();System.out.println("Running with: " + inputArguments);while (true) {printMaxMemory();consumeSpace();}} catch (OutOfMemoryError e) {freeSpace();printMaxMemory();}}static void printMaxMemory() {long currentMaxMemory = Runtime.getRuntime().maxMemory();if (currentMaxMemory != lastMaxMemory) {lastMaxMemory = currentMaxMemory;System.out.format("Runtime.getRuntime().maxMemory(): %,dK.%n", currentMaxMemory / 1024);}}static void consumeSpace() {objects.add(new int[1_000_000]);}static void freeSpace() {objects.clear();}
}

该代码通过循环中的新int [1_000_000]分配内存块,并检查当前已知可用于JVM运行时的内存。 每当发现最后一个已知的内存大小发生变化时,它都会通过打印Runtime.getRuntime()。maxMemory()的输出来报告该变化,类似于以下内容:

Running with: [-Xms2048M, -Xmx2048M]
Runtime.getRuntime().maxMemory(): 2,010,112K.

确实- 即使我已指定JVM使用2G堆,运行时也无法以某种方式找到其中的85M 。 您可以通过将Runtime.getRuntime()。maxMemory()的输出转换为MB(用2,010,112K除以1024 来仔细检查我的数学运算。结果将等于1,963M,与2048M相差85M。

寻找根本原因

在能够重现案例之后,我记下了以下笔记–使用不同的GC算法运行似乎也会产生不同的结果:

GC算法 Runtime.getRuntime()。maxMemory()
-XX:+ UseSerialGC 2,027,264千
-XX:+ UseParallelGC 2,010,112千
-XX:+ UseConcMarkSweepGC 2,063,104千
-XX:+ UseG1GC 2,097,152千

除了G1完全消耗了我给该进程分配的2G内存外,其他所有GC算法似乎都始终丢失半随机的内存。

现在是时候深入研究JVM 的源代码了,在CollectedHeap的源代码中,我发现了以下内容:

// Support for java.lang.Runtime.maxMemory():  return the maximum amount of
// memory that the vm could make available for storing 'normal' java objects.
// This is based on the reserved address space, but should not include space
// that the vm uses internally for bookkeeping or temporary storage
// (e.g., in the case of the young gen, one of the survivor
// spaces).
virtual size_t max_capacity() const = 0;

我不得不承认答案是非常隐蔽的。 但是,仍然有一些真正的好奇心可以找到的提示–指的是在某些情况下,堆大小计算中可能会排除一个幸存空间

从这里一直是顺风顺水–打开GC日志记录发现,实际上,使用2G堆,串行,并行和CMS算法都将幸存空间的大小恰好设置为缺少的差值。 例如,在上面的ParallelGC示例中,GC日志记录演示了以下内容:

Running with: [-Xms2g, -Xmx2g, -XX:+UseParallelGC, -XX:+PrintGCDetails]
Runtime.getRuntime().maxMemory(): 2,010,112K.... rest of the GC log skipped for brevity ...PSYoungGen      total 611840K, used 524800K [0x0000000795580000, 0x00000007c0000000, 0x00000007c0000000)eden space 524800K, 100% used [0x0000000795580000,0x00000007b5600000,0x00000007b5600000)from space 87040K, 0% used [0x00000007bab00000,0x00000007bab00000,0x00000007c0000000)to   space 87040K, 0% used [0x00000007b5600000,0x00000007b5600000,0x00000007bab00000)ParOldGen       total 1398272K, used 1394966K [0x0000000740000000, 0x0000000795580000, 0x0000000795580000)

从中您可以看到Eden空间设置为524,800K,两个幸存者空间(从和到)都设置为87,040K,旧空间的大小为1,398,272K。 将Eden,Old和一个幸存者空间加在一起总计为2,010,112K,这证实丢失的85M或87,040K确实是剩余的幸存者空间

摘要

阅读该文章后,您现在对Java API实现细节有了新的认识。 下次某些工具将总可用堆大小可视化为略小于Xmx指定的堆大小时,您会知道差值等于其中一个Survivor空间的大小。

我必须承认,这一事实在日常编程活动中并不是特别有用,但这不是该帖子的重点。 取而代之的是,我写了一篇文章,描述了我一直在优秀工程师中寻找的一个特殊特性- 好奇心 。 优秀的工程师一直在寻找理解某件事如何以及为什么以它的方式起作用的方法。 有时答案仍然是隐藏的,但我仍然建议您尝试寻求答案。 最终,沿途积累的知识将开始带来红利。

翻译自: https://www.javacodegeeks.com/2015/02/jvm-access-less-memory-specified-via-xmx.html

jvm内存 大于 xmx

jvm内存 大于 xmx_为什么我的JVM访问的内存少于通过-Xmx指定的内存?相关推荐

  1. 为什么我的JVM访问的内存少于通过-Xmx指定的内存?

    "嘿,你能来看看奇怪的东西吗?" 这就是我开始研究一个支持案例的方式,该案例将我引向了这篇博客文章. 当前的特殊问题与不同的工具报告了有关可用内存的不同数字有关. 简而言之,一位工 ...

  2. java jvm内存地址_深入Java虚拟机——JVM内存详解

    在C++中,程序员拥有每一个对象的所有权,但与此同时还肩负着释放对象内存空间的责任:而Java由于有了虚拟机的帮助,程序员拥有对象的所有权的同时不再需要释放对象的内存空间.由于是JVM自动进行对象内存 ...

  3. jvm内存参数配置_idea中设置JVM参数,简单理解JVM常见参数,JVM调优简单入门

    前面学习了JVM的内存分布,今天就来验证下.顺便通过测试学习一下JVM的几个参数,不过测试是在idea中,所以先要在idea上设置JVM参数. 一.idea设置全局的JVM参数 一共三步,第一步在菜单 ...

  4. 直接内存与元空间_深入浅出 JVM 内存管理

    Java岗位面试,JVM是对程序员基本功考察,通常会问你对JVM了解吗? 可以分几部分回答这个问题,首先JVM内存划分 | JVM垃圾回收的含义 | 有哪些GC算法 以及年轻代和老年代各自特点等等.1 ...

  5. 【Java书笔记】:《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》第2部分-自动内存管理,第3部分-虚拟机执行子系统,第5部分-高效并发

    作者:周志明 整理者GitHub:https://github.com/starjuly/UnderstandingTheJVM 第2部分-自动内存管理 第2章 Java内存区域与内存溢出异常 2.2 ...

  6. java jvm内存分配_JVM系列一:JVM内存组成及分配

    java内存组成介绍:堆(Heap)和非堆(Non-heap)内存 按照官方的说法:"Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配.堆是在 Java 虚 ...

  7. 内存详解mdash;mdash;理解 JVM 如何使用 AIX 上的本机内存

    理解 JVM 如何使用 AIX 上的本机内存 Java™ 堆耗尽并不是造成 java.lang.OutOfMemoryError 的惟一原因.如果本机内存 耗尽,则会发生普通调试技巧无法解决的 Out ...

  8. jvm性能调优 - 05对象在JVM内存中的分配和流转

    文章目录 前文回顾 大部分正常对象都优先在新生代分配内存 到底什么情况下会触发新生代的垃圾回收? 长期存活的对象会躲过多次垃圾回收? 老年代会垃圾回收吗? 关于新生代和老年代的对象分配,这就完了吗? ...

  9. java加快内存回收_java内存管理之垃圾回收及JVM调优

    GC(garbage Collector 垃圾收集器) 作用:a.内存的动态分配:b.垃圾回收 注:Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配. 一.垃圾标记 程序计数器.J ...

最新文章

  1. iOS 关于.tbd与.dylib用法
  2. python 转成摩尔斯电码_一篇文章教会你摩尔斯码
  3. 华为交换机—RRPP协议
  4. Java程序员如何做到Java架构师
  5. java移动端接口测试_借助Charles来测试移动端-下篇
  6. js滚动条下拉一定值_JS逆向 | 无限Debugger之淘大象
  7. vue v-if 和 v-show 的知识点
  8. Shell脚本-tr 将大写字母变为小写
  9. win10字体模糊发虚怎么回事?win10字体模糊发虚电脑问题还是系统问题?
  10. 致敬!百里煤海战斗在第二战线上的人们
  11. Java开发微信小程序(三)用小程序给用户推送服务消息
  12. 浙江省乡村快递寄件数据分析-快递100百递指数
  13. formula的java用法_java-@Formula无法在休眠状态下与对象一起使用
  14. [AV1] Segment
  15. 微信小程序token过期后重新执行失效的请求封装(用户无感刷新token)
  16. GPS坐标系转换(标准坐标系WGS84转GCJ-02火星坐标系)
  17. 计算机网络技术的研究现状,计算机网络技术发展研究
  18. reverse()和reverse_copy()用法
  19. 让div在body中居中显示
  20. 软件工程期末复习笔记(文末有PDF版本)

热门文章

  1. P7276-送给好友的礼物【dp】
  2. 欢乐纪中某B组赛【2019.1.27】
  3. 【ajax】readyState=4并且status=200时,还进error方法
  4. 一次堆外内存泄露的排查过程
  5. 彻底理解HashMap的元素插入原理
  6. 你知道面试官是如何刷人的吗
  7. Jsoup代码解读之七-实现一个CSS Selector
  8. 阿里巴巴对Java编程【命名风格】的规约
  9. uni-app打包h5
  10. 已知两个链表A和B分别表示两个集合,其元素递增排列。请设计算法求出两个集合A和集合B的差集(近由在A中出现而不再B中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。