我最近一直在研究基准测试,我一直对记录程序数据等感兴趣.我有兴趣知道我们是否可以实现自己的内存使用代码并在我们的程序中有效地实现我们自己的时间消耗代码.我知道如何检查代码运行所需的时间:
public static void main(String[]args){
long start = System.currentTimeMillis();
// code
System.out.println(System.currentTimeMillis() - start);
}
Run Code Online (Sandbox Code Playgroud)
我还研究了Robust Java基准测试,第1部分:问题,本教程非常全面.显示的负面影响System.currentTimeMillis();.然后教程建议我们使用System.nanoTime();(使其更准确?).
我还研究了使用Java确定内存使用情况以获取内存使用情况.该网站显示了如何实施它.提供的代码看起来无穷无尽,因为此人正在呼叫
long L = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
在此之后,他打电话给System.gc();(4*4)= 16次.然后再次重复该过程.这不也占用记忆吗?
那么在结论中,是否可以在java程序中实现高效的基准测试代码?
我需要分析Java中某些算法的复杂性.为此,我计划提供大量输入并测量Java实现所花费的时间.检查某些代码行之间的时间最准确,最准确的方法是什么?我需要精确到毫秒......
几个小时前我回答了另一个Stack Overflow问题,结果非常令人惊讶.答案可以在这里找到.答案是/部分错误,但我觉得专注于字节添加.
严格来说,它实际上是字节到长的添加.
这是我一直使用的基准代码:
public class ByteAdditionBenchmark {
private void start() {
int[] sizes = {
700_000,
1_000,
10_000,
25_000,
50_000,
100_000,
200_000,
300_000,
400_000,
500_000,
600_000,
700_000,
};
for (int size : sizes) {
List<byte[]> arrays = createByteArrays(size);
//Warmup
arrays.forEach(this::byteArrayCheck);
benchmark(arrays, this::byteArrayCheck, "byteArrayCheck");
}
}
private void benchmark(final List<byte[]> arrays, final Consumer<byte[]> method, final String name) {
long start = System.nanoTime();
arrays.forEach(method);
long end = System.nanoTime();
double nanosecondsPerIteration = (end - start) * 1d / arrays.size();
System.out.println("Benchmark: …Run Code Online (Sandbox Code Playgroud) 我有这个代码正在测试Calendar.getInstance().getTimeInMillis()vs System.currentTimeMilli():
long before = getTimeInMilli();
for (int i = 0; i < TIMES_TO_ITERATE; i++)
{
long before1 = getTimeInMilli();
doSomeReallyHardWork();
long after1 = getTimeInMilli();
}
long after = getTimeInMilli();
System.out.println(getClass().getSimpleName() + " total is " + (after - before));
Run Code Online (Sandbox Code Playgroud)
我想确保没有JVM或编译器优化发生,因此测试将是有效的并且实际上会显示出差异.
怎么样?
编辑:我改变了代码示例,以便更清楚.我在这里检查的是在不同的实现中调用getTimeInMilli()需要多长时间 - Calendar vs System.
StackOverflow上多次询问过这个问题,但没有一个是基于性能的.
在Effective Java书中给出了它
如果
String s = new String("stringette");在循环或频繁调用的方法中发生,则可以不必要地创建数百万个String实例.改进版本只是以下内容:
String s = "stringette";此版本使用单个String实例,而不是每次执行时都创建一个新实例.
所以,我尝试了两者,发现性能有了显着提高:
for (int j = 0; j < 1000; j++) {
String s = new String("hello World");
}
Run Code Online (Sandbox Code Playgroud)
需要大约399 372纳秒.
for (int j = 0; j < 1000; j++) {
String s = "hello World";
}
Run Code Online (Sandbox Code Playgroud)
大约需要23 000纳秒.
为什么会有这么多的性能提升?内部是否有任何编译器优化?
假设我们在集合中有一些项目,我们想要使用某个比较器对它们进行排序,期望列表中的结果:
Collection<Item> items = ...;
Comparator<Item> itemComparator = ...;
Run Code Online (Sandbox Code Playgroud)
其中一种方法是对列表中的项进行排序,例如:
List<Item> sortedItems = new ArrayList<>(items);
Collections.sort(sortedItems, itemComparator);
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用排序流:
List<Item> sortedItems = items
.stream()
.sorted(itemComparator)
.collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
我想知道,哪种方法更有效率?排序流是否有任何优点(如多核上的紧固排序)?
从运行时复杂性/速度的角度来看,效率很高.
我不相信自己能够实现一个完美的基准,学习SortedOps并没有真正启发我.
我正在做这样的事情:
for (int i = 0; i < 100000; i++) {
System.out.println( i );
}
Run Code Online (Sandbox Code Playgroud)
基本上,我计算一个整数并输出一个大约10K-100K次的字符串,然后需要将结果写入system.out,每个结果用换行符分隔.
实现这一目标的最快方法是什么?
我想知道String.format在Java应用程序中使用是否很好而不是StringBuilder......所以,我只是编写一个简单的测试,如下所示:
public static void main(String[] args) {
int i = 0;
Long start = System.currentTimeMillis();
while (i < 10000) {
String s = String.format("test %d", i);
i++;
}
System.out.println(System.currentTimeMillis() - start);
i = 0;
start = System.currentTimeMillis();
while (i < 10000) {
String s = new StringBuilder().append("test ").append(i).toString();
i++;
}
System.out.println(System.currentTimeMillis() - start);
}
Run Code Online (Sandbox Code Playgroud)
结果在哪里:
238
15
Run Code Online (Sandbox Code Playgroud)
所以,如果我的测试有效,StringBuilder则速度快于String.format.好.现在,我开始思考如何String.format运作.这是一个简单的字符串连接"test " + i吗?
StringBuilder连接和String.format?之间的区别是什么?有没有像简单String.format …
我知道使用BufferedReader(包装FileReader)将比使用BufferedInputStream(包装FileInputStream)慢得多,因为原始字节必须转换为字符.但我不明白为什么它这么慢!以下是我正在使用的两个代码示例:
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] byteBuffer = new byte[bufferSize];
int numberOfBytes;
do {
numberOfBytes = inputStream.read(byteBuffer, 0, bufferSize);
} while (numberOfBytes >= 0);
}
finally {
inputStream.close();
}
Run Code Online (Sandbox Code Playgroud)
和:
BufferedReader reader = new BufferedReader(new FileReader(filename), bufferSize);
try {
char[] charBuffer = new char[bufferSize];
int numberOfChars;
do {
numberOfChars = reader.read(charBuffer, 0, bufferSize);
} while (numberOfChars >= 0);
}
finally {
reader.close();
}
Run Code Online (Sandbox Code Playgroud)
我已尝试使用各种缓冲区大小的测试,所有缓冲区大小都是150兆字节的文件.以下是结果(缓冲区大小以字节为单位;时间以毫秒为单位):
Buffer Input
Size Stream Reader
4,096 145 497
8,192 125 465
16,384 …Run Code Online (Sandbox Code Playgroud) 我有一个Java程序(使用JDK 7u80编译),它广泛使用"JavaScript"ScriptEngine(JSR-223).我注意到,与Java 7运行时环境(JRE 7u80)相比,在Java 8运行时环境(JRE 8u65)下执行时,我的程序运行速度极慢.
我已经整理了以下SSCCE来演示问题,然后在同一台Windows PC上的Java 7和Java 8下执行它:
import javax.script.*;
public class SSCCE {
public SSCCE() {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine js = sem.getEngineByName("JavaScript");
long t = 0;
int i = 0;
String gJs = "function ip2long(ip) {";
gJs += "var aIP = ip.split(\".\");";
gJs += "return (aIP[0] * Math.pow(256, 3)) + (aIP[1] * Math.pow(256, 2)) + (aIP[2] * 256) + (aIP[3] * 1);";
gJs += "}";
gJs += "function long2ip(l) {";
gJs += "if (!isNaN(l) …Run Code Online (Sandbox Code Playgroud) java ×10
performance ×4
benchmarking ×2
java-8 ×2
arraylist ×1
java-stream ×1
jvm ×1
optimization ×1
scriptengine ×1
string ×1