为什么我的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()的输出除以2,010,112K除以1024来转换为MB,从而仔细检查我的数学运算。结果将等于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;

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

java-heap-permgen-不同的内存池

从这里一直是顺风顺水–打开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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux怎么安装高德导航软件,高德地图车机版如何安装?高德地图车机版安装教程...

高德地图车机版是高德为汽车车载机提供的一个专用版本&#xff0c;对于车主们来说有时候用手机导航实在是非常不方便&#xff0c;不仅屏幕小而且还可能中途来个电话什么的。高德地图车机版可以帮你的车载机装上导航地图&#xff0c;就算你不想买导航设备也能让你的车子为你导航…

Dropwizard,MongoDB和Gradle实验

介绍 我使用Dropwizard&#xff0c;MongoDB和Gradle创建了一个小项目。 它实际上是从一个实验性的Guava缓存开始的&#xff0c;作为将计数器发送到MongoDB&#xff08;或任何其他DB&#xff09;的缓冲区。 我也想尝试MondleDB插件的Gradle。 接下来&#xff0c;我想创建某种接口…

在wp中,使用NavigationService.Navigate导航页面出现错误

我们在WP项目中采用页面导航时候&#xff0c;经常会使用以下代码 NavigationService.Navigate(new Uri("/Page1.xaml",UriKind.Relative));但是&#xff0c;有的时候会出现错误&#xff1a; "Error 1 An object reference is required for the non-static field…

SSDT – Error SQL70001 This statement is not recognized in this context-摘自网络

March 28, 2013 — arcanecode One of the most common errors I get asked about when using SQL Server Data Tools (SSDT) Database Projects is the error “This statement is not recognized in this context”. This is actually a pretty simple error to fix. Envisi…

带有JAX-RS和PrimeFaces的RESTful图表

通常&#xff0c;利用图表提供数据的可视表示很有用。 PrimeFaces提供制图解决方案&#xff0c;可轻松将数据的可视表示形式添加到Web和移动应用程序中。 如果将PrimeFaces图表组件与RESTful Web服务数据结合使用&#xff0c;我们可以创建自定义图表&#xff0c;以适合桌面和移…

UVAlive 6131 dp+斜率优化

这道题和06年论文《从一类单调性问题看算法的优化》第一道例题很相似。 题意&#xff1a;给出n个矿的重量和位置&#xff0c;这些矿石只能从上往下运送&#xff0c;现在要在这些地方建造m个heap&#xff0c;要使得&#xff0c;sigma距离*重量最小。 思路&#xff1a;O(n ^ 3)的…

c语言程序整数四则运算,c语言中三个整数随机的四则运算

满意答案hors10722014.01.06采纳率&#xff1a;58% 等级&#xff1a;12已帮助&#xff1a;18274人#include #include #include #define N 10 //随机出10道题目int main(){int num1, num2, num3, count0, result,resultTrue,flag;//result:用户输入结果 resultTrue:正确结果 …

带有调试器的Apache Camel Eclipse工具

大约2个月前&#xff0c; Lars Heineman在 JBoss工具堆栈中的博客中介绍了改进的Apache Camel Eclipse工具。 在即将发布的版本中&#xff0c;他们将Camel调试器与本机Eclipse调试器集成在一起&#xff0c;因此当您使用断点时&#xff0c;您将获得Eclipse调试体验&#xff0c;…

HarmonyOS的功能及场景应用

一、基本介绍 鸿蒙HarmonyOS主要应用的设备包括智慧屏、平板、手表、智能音箱、IoT设备等。具体来说&#xff0c;鸿蒙系统是一款面向全场景(移动办公、运动健康、社交通信、媒体娱乐等)的分布式操作系统&#xff0c;能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备…

SX-BOX试用笔记

1.今天开始试用SX-BOX&#xff0c;我将用它来做自己平时的开发和文档的工作&#xff0c;因为我的职责是一个程序员。 1.屏幕如果支持更大的也清晰的话&#xff0c;我会感觉很舒服。 2.USB设备插入还无法识别。。。 3.现在开始安装开发工具&#xff0c;目前我打算在上面安装Adob…

c语言成绩转换绩点,如何将平时成绩转化为GPA成绩?

新东方留学生资料下载姓名手机号短信验证码图片验证码年级请选择5年级6年级7年级8年级9年级高一高二高三高三复习大一大二大三大四大五研一研二研三博一博二在职课程请选择雅思托福GREGMATSAT其他行政区请选择请选择请选择{"name":{"label":"姓名&quo…

Hibernate查询缓存如何工作

介绍 既然我已经介绍了实体和集合缓存&#xff0c;现在该研究查询缓存的工作原理了。 查询缓存与实体严格相关&#xff0c;它在搜索条件和满足该特定查询过滤器的实体之间绘制关联。 像其他Hibernate功能一样&#xff0c;查询缓存也不像人们想象的那么琐碎。 实体模型 对于我…

Javascript学习笔记1 数论

1.Javascript不用担心内存的回收与对象的销毁&#xff01; 2.Javascript有&#xff1a;infinity、NaN全局变量表示 被0整除的无穷 和 非数字。undefined和null表示 未定义 和 空&#xff0c;undefined和null可以互换&#xff0c;判别二者需用 全等 号&#xff08;不光判断值&…

JavaFX技巧20:有很多需要展示的地方吗? 使用画布!

JavaFX应用程序似乎有两种&#xff1a;第一种使用带有节点和CSS样式的场景图&#xff0c;第二种使用单个画布。 但是&#xff0c;将这两种方法混合使用是完全合法的。 尤其是当您的应用程序必须显示大量详细信息时&#xff0c;您很容易最终创建成千上万个节点。 即使JavaFX的整…

VirtualBox命令更改虚拟硬盘空间

主要是使用VBoxManage命令来操作第一步&#xff1a;打开CMD&#xff0c;进入到virtualbox存放虚拟机的目录中(win7 系统可以直接在文件夹空白处按住shift键右键鼠标选择[在此处打开命令窗口])&#xff0c;输入[vboxmanage list hdds]可以查看所有的虚拟机的信息&#xff0c;这里…

华为手机老是android自动升级,华为手机系统怎么升级 华为手机升级系统的两种方法...

华为手机使用的均为安卓系统&#xff0c;升级方法有多种&#xff0c;各位可以根据条件不同自行选择升级。华为手机升级系统的两种方法方法一&#xff1a;手机联网更新首先把手机联网。点击设置。向下拖动点击最后一项“关于手机”点击“系统软件更新”。点击在线升级即可。友情…

linux网络体系架构

原创kylin_zeng:http://blog.csdn.net/kylin_fire_zeng 本文参考国嵌视频教程&#xff0c;再此感谢国嵌教育。 一、协议栈层次对比&#xff1a; 1&#xff09;网络接口层把数据链路层和物理层合并在了一起&#xff0c;提供访问物理设备的驱动程序&#xff0c;对应的网络协议主…

android 自定义弹窗diss,Android中自定义PopupWindow,动态弹窗。

我的第一篇博客&#xff0c;咱们直奔主题。先上个效果图在android中自定义PopupWindow&#xff1a;1、首先定义好你想要显示的窗口的布局文件&#xff0c;再实例化一个View对象&#xff1a;窗口布局可灵活变化&#xff0c;dialog_layout.xml代码如下&#xff1a;android:id&quo…

拼图项目的动机和目标

几周前&#xff0c;我写了一篇关于Jigsaw项目如何破坏现有代码的文章 。 那么&#xff0c;我们能得到什么回报呢&#xff1f; 让我们看一下项目解决的痛点及其在Java 9中解决问题的目标。 系列 这篇文章是正在进行的有关拼图项目系列的一部分。 按照推荐的顺序&#xff08;不同…

android中按一个按钮弹出字,允许用户在Android中长按一次即可编辑按钮文字

我想允许App用户在Android中更改Button文本。 当用户单击按钮时&#xff0c;它应该执行某些操作&#xff0c;但是当他/她长按按钮时&#xff0c;将弹出一个编辑文本&#xff0c;并且无论用户键入什么内容都应另存为按钮文本。到目前为止&#xff0c;我已经完成了以下操作。btn1…