我想在内存使用效率方面比较Java程序的不同实现。有不同的使用场景被表述为JUnit测试用例。实际上,所有的代码都是开源的:https://github.com/headissue/cache2k-benchmark
获取Java程序已用内存的一般方法是:Runtime.getRuntime()。totalMemory()-运行时.getRuntime()。freeMemory()
,当然也可以使用JMX接口来获取这些值。
但是,已使用内存的确定值不可靠。可能的原因:
到目前为止,我尝试切换到串行GC,并在读出值之前使用运行时.getRuntime().gc()
强制进行垃圾回收。我把这个实验代码放在了:https://github.com/cruftex/java-memory-benchmark
如果我在读取值之前执行三次< code>gc调用,我会得到以下输出(< code > mvn test | grep loop count with JDK 1 . 7 . 0 _ 51):
testBaseline1: used=1084168, loopCount=0, total=124780544
testBaseline2: used=485632, loopCount=0, total=124780544
testBaseline3: used=483760, loopCount=0, total=124780544
testBaseline4: used=483800, loopCount=0, total=124780544
testBaseline: used=484160, loopCount=0, total=124780544
test100MBytes: used=105341496, loopCount=0, total=276828160
test127MBytes: used=133653088, loopCount=0, total=469901312
test27MBytes: used=28795528, loopCount=0, total=317755392
test10MBytes: used=10969776, loopCount=0, total=124784640
通过四次< code>gc调用(签入时),我得到:
testBaseline1: used=483072, loopCount=0, total=124780544
testBaseline2: used=483728, loopCount=0, total=124780544
testBaseline3: used=483768, loopCount=0, total=124780544
testBaseline4: used=483808, loopCount=0, total=124780544
testBaseline: used=483848, loopCount=0, total=124780544
test100MBytes: used=105341504, loopCount=0, total=276828160
test127MBytes: used=133653096, loopCount=0, total=469901312
test27MBytes: used=28795536, loopCount=0, total=139239424
test10MBytes: used=10969784, loopCount=0, total=124784640
因此,经验表明,对于四次GC调用,结果似乎是正确的。从GC统计输出中,我可以看到第一次GC填充了终身空间,第四次GC调用减少了它:
2015-01-08T02:30:35.069+0100: [Full GC2015-01-08T02:30:35.069+0100: [Tenured: 0K->1058K(83968K)
2015-01-08T02:30:35.136+0100: [Full GC2015-01-08T02:30:35.136+0100: [Tenured: 1058K->1058K(83968K)
2015-01-08T02:30:35.198+0100: [Full GC2015-01-08T02:30:35.198+0100: [Tenured: 1058K->1058K(83968K)
2015-01-08T02:30:35.263+0100: [Full GC2015-01-08T02:30:35.264+0100: [Tenured: 1058K->471K(83968K)
得到内存使用值的最终代码是:
try {
Runtime.getRuntime().gc();
Thread.sleep(55);
Runtime.getRuntime().gc();
Thread.sleep(55);
Runtime.getRuntime().gc();
Thread.sleep(55);
Runtime.getRuntime().gc();
Thread.sleep(55);
} catch (Exception ignore) { }
long _usedMem;
long _total;
long _total2;
long _count = -1;
// loop to get a stable reading, since memory may be resized between the method calls
do {
_count++;
_total = Runtime.getRuntime().totalMemory();
try {
Thread.sleep(12);
} catch (Exception ignore) { }
long _free = Runtime.getRuntime().freeMemory();
_total2 = Runtime.getRuntime().totalMemory();
_usedMem = _total - _free;
} while (_total != _total2);
System.out.println(_testName + ": used=" + _usedMem + ", loopCount=" + _count + ", total=" + _total);
我不确定这种方法是否一直产生可靠的结果。所以有一些问题:
更新:
虽然上面的一些问题与GC相关,但实际问题不是。我喜欢找出应用程序在单个时间点的内存使用情况。一个可能的解决方案也是对所有对象进行深度搜索并总结大小。
更新2:
与此同时,我确实写了一篇关于这个问题的博文,讨论了如何测量实际内存使用量的不同方法:
https://cruft ex . net/2017/03/28/The-6-Memory-Metrics-You-Should-Track-in-Your-Java-benchmarks . html
首先,你应该看看JMH找出一个适当的Javabechmark应该怎么做。
调用Runtime.getRuntime(). gc()
绝对是一种糟糕的做法——无论是在现实生活中还是在对GC进行基准测试时。至少举一个原因,通过强制GC循环,您将直接惩罚任何GC算法的性能。
此外,您不能通过仅执行大约4个GC周期来比较各种GC算法。您应该运行一个合适的GC基准测试——参见JMH,您至少需要运行相当长的时间——根据堆的大小,这可能是10分钟,也可能是几个小时...
我认为开始时最好的办法是长时间运行一个类似JMH的基准测试(大约30分钟),收集GC日志并处理GC日志中的各种统计数据...至少要有某种合理的比较作为开始。
我想比较Java程序的不同实现的内存使用效率。
一种选择是用以下代码运行程序:
-Xloggc:gc.log_impl1 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
然后,切换到实现 2 并重新运行
-Xloggc:gc.log_impl2 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
然后下载HPjeter,将两个文件加载到控制台并使用比较gc功能。图表中可能有一点倾斜,但您会很好地了解程序内存配置文件的不同之处。
我不会试图综合援引指导性案例。
我也为这个问题而苦苦挣扎,并有兴趣知道是否有任何标准方法。
我能做的最好的事情就是告诉JVM在运行后和下一次运行之前调用以下方法来尽可能多地收集垃圾:
GcFinalization.awaitFullGc();
此方法来自番石榴测试库包,可以作为 Maven 依赖项添加为:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>18.0</version>
</dependency>
实现如下所示:
public static void awaitFullGc() {
final CountDownLatch finalizerRan = new CountDownLatch(1);
WeakReference<Object> ref = new WeakReference<Object>(
new Object() {
@Override protected void finalize() { finalizerRan.countDown(); }
});
await(finalizerRan);
awaitClear(ref);
// Hope to catch some stragglers queued up behind our finalizable object
System.runFinalization();
}
这为每次运行提供了非常一致的结果,并使CPU用户时间(来自ThreadMXBean
)非常接近纳米时间(来自System.currentTimeMills
)。我在这些测量中主要关注的是运行时间,但与中间没有此调用的版本相比,内存使用也是一致的。
问题内容: 对于大学,我进行字节码修改,并分析它们对Java程序性能的影响。因此,我需要Java程序(在生产中最好使用的Java程序)和适当的基准测试。例如,我已经有了HyperSQL,并通过基准程序PolePosition来衡量其性能。在没有JIT编译器的JVM上运行的Java程序。谢谢你的帮助! PS:我不能使用程序来对JVM或Java语言本身的性能进行基准测试(例如Wide Finder)。
我有一个应用程序,我想使用对其进行基准测试。任何有关此集成的参考都将是有用的。
我定期关注GitHub Rakudo存储库,查看Rakudo编译器发生了哪些变化。 我有时会看到提交,其中单个函数的速度提高了一定的百分比,时间如下图所示。 评估这一点的工作流是什么?我很想了解这一点,以便了解您的功能是如何执行的,并相应地进一步优化,从而为Rakudo的发展做出贡献。 我在这里阅读帮助。我谷歌了一下,但找不到此信息。我还通过命令行选项了解了MoarVM分析器,它会生成输出。要寻找
对于我的单元测试,我使用以下注释: @runwith(SpringJunit4ClassRunner.class) @SpringBootTest(classes=MyApplication.class) 我的问题发生在我试图用Selenium测试GUI时。在我的gui测试中,我调用了一些页面并验证了html消息的内容。 我不需要模拟,我需要在我的测试前开始申请。什么是优雅的方式来做到这一点? 注
问题内容: 除了以下内容之外,是否有其他方法/软件可以给出执行用Swift编写的代码块所需的准确时间? 问题答案: 如果您只想为代码块提供独立的计时功能,则可以使用以下Swift助手功能: 前者将注销给定代码段所需的时间,后者将返回该时间作为浮点数。作为第一个变体的示例: 将注销类似: map()经过的时间:0.0617449879646301 s 请注意,Swift基准测试会根据您选择的优化级别