在JVisualVM / JConsole中的System.gc()对比GC按钮 [英] System.gc() vs GC button in JVisualVM/JConsole

查看:148
本文介绍了在JVisualVM / JConsole中的System.gc()对比GC按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在测试我处理XML模式的概念验证原型,并构建了一个非常耗内存的用于树自动机的外部库(为此我有源代码),我想绘制真正的峰值(堆)内存消耗量随着架构规模的增加而变化(所用的度量符合我的知识库并且不会影响问题),或者至少有一个合理的近似值。

为了给出一个数量级,对于实际峰值为100MB的运行(我测试了它运行几次完全相同的输入/参数配置,强制jvm内存使用-Xmx和-Xms减少值,I在main线程中获得异常java.lang.OutOfMemoryError:超出GC开销限制 <100MB,结果稳定且可重复)它占用大约1.1GB,这就是为什么它对我来说非常重要真正的数字,因为它们有很大的不同!



我花了最近10天的时间阅读关于我们的问题b和在stackoverflow中,我真正知道的是:
$ b $ 1)System.gc()建议GC运行,不强制它,所以它是不可能依靠它来检测内存使用高峰的b / b

2)通常建议的是计算对象占用(我看到 SizeOf 这个项目,我试过并且工作正常,即使它不符合我的需要),这对我来说是不可行的,因为重大的内存分配会发生以不同的方法创建大量的集合(集合,列表和映射)迭代器,被称为非常多的次数(对于我记忆中的每10分钟运行数百万次),所以这将非常困难检测所有涉及的对象并执行总和(我在几天的内存消耗图中调试了很多次运行,而不能只识别一个瓶颈)

3)无法轻易获得一种方法的内存占用(表示为对象内存分配的高峰)

事实是,我亲身体验过System.gc()调用不可靠(例如,但是当我在JVisualVM或Jconsole中按下GC按钮时,永远不会 ,因此不会执行相同配置的不同运行,因为System.gc无法运行GC或拒绝这样做。



所以我的问题是:调用它们的按钮实现(我没有尝试它,但为了什么我读到现在看来,使用jconsole.jar与 attach api )将不同于直接从我的代码调用System.gc(),从而解决我的问题?如果不是的话,你如何解释该按钮的确定性行为?

到现在为止,我做了一些手动测试,模式大小(对于这种测量,模式是从一​​个单一的复杂性参数自动生成的),我绘制了预期的曲线,如果我不能获得更好的解决方案,我想将我的代码作为外部的jar来运行-Xmx / -Xms等于略低于我对预期内存峰值的预测,捕获外部进程ErrorStream中的OutMemoryException并使用增加的内存重新启动,直到实现完整运行。 (如果幼稚的记忆预测不够健壮,我会运用适当的机器学习技术)。我知道这不是一个优雅的解决方案,但在我的情况下(学术界),我可以花费一些额外的时间来进行这些测量。系统信息(机器是Fedora 17,64位):



系统信息(机器是Fedora 17,64位):


Java版本1.7.0_04
Java™SE运行时环境(build 1.7.0_04-b20)
Java HotSpot™64位服务器虚拟机(构建23.0-b21,混合模式)

在此先感谢您,
Alessandro

解决方案

我有相当多的积极经验,这个简单的方法:

  System.gc(); 
Thread.sleep(500);
System.gc();

一个GC运行通常是不够的,因为对象可能会在最终确定中复活。因此额外的内存在第二次GC运行中被释放。请注意,这个以及其他看似更智能的方法都是启发式的,并且相当依赖在JVM的确切版本上,包括其GC配置。但在很多情况下,您不会对通用性感兴趣:如果它现在可以正常工作,并且可以进行测量,那么这就是要走的路。


I'm currently testing my proof of concept prototype dealing with XML schema, and built around a very memory consuming external library for tree automata (for which I've got the sources), I'd like to plot "real peak" (heap) memory consumption of the different runs with increasing schema sizes (the metric used fits my purpouse and do no affect the question), or at least a reasonable approximation of it.

To give an order of magnitude, for a run with a real peak of 100MB (I tested it running several times exactly the same configuration of input/parameters, forcing the jvm memory with -Xmx and -Xms to decreasing value, I get Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded < 100MB, with stable and repeatable results) it occupy around 1.1GB, that's why it is extremely important for me to get the real number, because they differs a lot!

I've spent the last 10 days reading questions on the web and in stackoverflow, what I actually know is:

1) System.gc() "suggest" a GC run, does not force it in any way, so it is not possible to rely on it for detecting memory usage peaks

2) What is usually suggested is to count object occupation (I saw SizeOf project for this, I tried and works fine, even if it does not fits my needs), that is not feasible for me because heavy memory allocation happens due to the creation of a lot of collection (set, list and map) iterators in different methods, called a very high number of times (say millions each for a run of 10 minutes for what I remember), so it would be extremely difficult to detect all the involved objects and performing the sums (I debugged many many runs in days with memory consumption graphs without being able to identify only a single bottle-neck)

3) There is no way to easily obtain the memory occupation of a method (expressed as the peak of object memory allocation)

The fact is that I experienced by myself that System.gc() calls are not reliable (e.g. different runs of the same configuration, different memory read after a System.gc() due to the GC being really called or not), but when I press the "GC button" in JVisualVM or Jconsole it never fails to run GC or refuses to do so.

So my question is: calling their implementation of that button (I didn't try it yet but for what I've read up to now it seems feasible using jconsole.jar with attach api) will differ from calling System.gc() directly from my code, thus solving my problem? If not, how do you explain the "deterministc behaviour" of that button?

Up to now I did some manual test of real memory peak given 10 increasing schema sizes (for this kind of measurement the schemas are automatically generated from a single "complexity parameter") and I plotted the expected curve, if I will not be able to obtain a better solution I want to run my code as an external jar with -Xmx/-Xms equal to slightly less than my prediction of the expected memory peak, catching the OutMemoryException in the external process ErrorStream and relaunching with increased memory until a complete run is achieved. (If the naive memory prediction will not be robust enough I will apply appropriate Machine Learning techniques). I know that this is not an elegant solution but in my scenario (academia) I can afford to spend some extra time for these measurements. If you have other suggestions or improvement to this bruteforce method you are (extremely) welcome to share them.

System info (machine is a Fedora 17, 64 bit):

java version "1.7.0_04" Java(TM) SE Runtime Environment (build 1.7.0_04-b20) Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

Thanks in advance, Alessandro

解决方案

I have quite a bit of positive experience with this trivial approach:

System.gc();
Thread.sleep(500);
System.gc();

One GC run is often not enough due to object finalization issues, where an object may be resurrected in finalization. Therefore additional memory is released in the second GC run.

Do note that this, as well as ony other, seemingly "smarter", approaches, are all heuristics and quite dependant on the exact version of JVM, including its GC configuration. But in many cases you will not be so much interested in generality: if it works right now and allows you to do your measurements, it is the way to go.

这篇关于在JVisualVM / JConsole中的System.gc()对比GC按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆