- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
以下代码
public class Main {
public static void main(String[] args) throws IOException {
File tmp = File.createTempFile("deleteme", "dat");
tmp.deleteOnExit();
RandomAccessFile raf = new RandomAccessFile(tmp, "rw");
for (int t = 0; t < 10; t++) {
long start = System.nanoTime();
int count = 5000;
for (int i = 1; i < count; i++)
raf.setLength((i + t * count) * 4096);
long time = System.nanoTime() - start;
System.out.println("Average call time " + time / count / 1000 + " us.");
}
}
}
在 Java 8 上,这运行良好(文件在 tmpfs 上,所以你会认为它是微不足道的)
Average call time 1 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
Average call time 0 us.
在 Java 10 上,随着文件变大,这个速度会变慢
Average call time 311 us.
Average call time 856 us.
Average call time 1423 us.
Average call time 1975 us.
Average call time 2530 us.
Average call time 3045 us.
Average call time 3599 us.
Average call time 4034 us.
Average call time 4523 us.
Average call time 5129 us.
有没有办法诊断这类问题?
是否有任何解决方案或替代方案可以在 Java 10 上高效运行?
注意:我们可以写入文件的末尾,但是这需要锁定它,我们希望避免这样做。
为了比较,在 Windows 10 上,Java 8(不是 tmpfs)
Average call time 542 us.
Average call time 487 us.
Average call time 480 us.
Average call time 490 us.
Average call time 507 us.
Average call time 559 us.
Average call time 498 us.
Average call time 526 us.
Average call time 489 us.
Average call time 504 us.
Windows 10、Java 10.0.1
Average call time 586 us.
Average call time 508 us.
Average call time 615 us.
Average call time 599 us.
Average call time 580 us.
Average call time 577 us.
Average call time 557 us.
Average call time 572 us.
Average call time 578 us.
Average call time 554 us.
UPDATE 系统调用的选择似乎在 Java 8 和 10 之间发生了变化。这可以通过在命令行开头添加 strace -f
来看到
在 Java 8 中,在内循环中重复以下调用
[pid 49027] ftruncate(23, 53248) = 0
[pid 49027] lseek(23, 0, SEEK_SET) = 0
[pid 49027] lseek(23, 0, SEEK_CUR) = 0
在 Java 10 中,重复以下调用
[pid 444] fstat(8, {st_mode=S_IFREG|0664, st_size=126976, ...}) = 0
[pid 444] fallocate(8, 0, 0, 131072) = 0
[pid 444] lseek(8, 0, SEEK_SET) = 0
[pid 444] lseek(8, 0, SEEK_CUR) = 0
特别是,fallocate
比 ftruncate
做的工作要多得多,而且所花费的时间似乎与文件的长度成正比,而不是与文件的长度成正比.
一种解决方法是;
fd
文件描述符使用反射这似乎是一个 hacky 解决方案。 Java 10 中是否有更好的替代方案?
最佳答案
Is there a way to diagnose this kind of problem?
您可以使用可识别内核的 Java 分析器,例如 async-profiler .
这是 JDK 8 显示的内容:
对于 JDK 10:
配置文件证实了您的结论,即 RandomAccessFile.setLength
在 JDK 8 上使用 ftruncate
系统调用,但在 JDK 10 上使用了更重的 fallocate
。
ftruncate
真的很快,因为它只更新文件元数据,而 fallocate
确实分配了磁盘空间(或 tmpfs
的情况下的物理内存)。
此更改旨在修复 JDK-8168628 : 扩展文件大小以映射它时的 SIGBUS。但后来意识到这是一个坏主意,并且在 JDK 11 中恢复了该修复:JDK-8202261 .
Is there any solution or alternative which works efficiently on Java 10?
有一个内部类 sun.nio.ch.FileDispatcherImpl
具有静态 truncate0
方法。它在底层使用 ftruncate
系统调用。您可以通过反射调用它,记住这是一个不受支持的私有(private) API。
Class<?> c = Class.forName("sun.nio.ch.FileDispatcherImpl");
Method m = c.getDeclaredMethod("truncate0", FileDescriptor.class, long.class);
m.setAccessible(true);
m.invoke(null, raf.getFD(), length);
关于java - Java 10 (Centos) 上的 RandomAccessFile.setLength 慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50450317/
我想编写一个附加到整数数组的过程,但 Delphi IDE 给我编译时错误“不兼容类型”。这是我的代码: procedure appendToIntegerArray(var intArr : arr
在 Delphi 中,可以创建该类型的数组 var Arr: array[2..N] of MyType; 这是一个由 N - 1 元素组成的数组,索引从 2 到 N。 如果我们声明一个动态数组
我正在尝试使用以下函数来设置动态数组的长度,该数组是 var 参数。当我尝试编译代码时只有一个错误: [dcc64 错误] lolcode.dpr(138): E2008 不兼容类型 function
当然,即使我也能做到...... var testarray : array of string; setlength(testarray, 5); 但是如果我想变得聪明并有一个过程来通过引用传递
这个问题可能会也可能不会解决我的问题 - 但我希望了解 Delphi/Windows 如何以可能导致此问题的方式运行。 我有一个使用 3rd 方组件来加载 Outlook .msg 文件的应用程序。
在某些情况下,我需要设置动态数组的大小,然后用零填充它。 类似于: procedure SetLengthAndZero(VAR X; NewSize: Integer); begin SetL
今天我偶然发现了一个导致我的数组损坏的问题。这是一个可重现的测试用例: unit Unit40; interface type TVertex = record X, Y: Double;
我一直在阅读 RandomAccessFile 并了解可以通过 setLength 将文件末尾截断为比文件短的长度。我试图将文件的“结尾”复制到新文件并截断开头。 例如:我想删除文件的前 1300
在 stringbuilder 中修剪到一定长度。 我应该使用什么? StringBuilder sb = new StringBuilder("203253/62331066
我有这个代码: [[self.receivedData objectForKey:[NSNumber numberWithInt:connection.tag]] setLength:0]; 重复三次
这个问题已经有答案了: Clear contents of a file in Java using RandomAccessFile (2 个回答) 已关闭 9 年前。 我正在尝试清除用 java
我正在发出异步请求,并且在 [responseData setLength:0]; 上收到 EXC_BAD_ACCESS 代码是: - (void)connection:(NSURLConnectio
我有以下代码来生成字符串的所有可能的子字符串: import java.util.*; public class PlayString { public static void main(St
我需要创建一个包含记录对象数组的类,但尝试使用 SetLength 会引发访问冲突错误。 考虑以下带有水果的树对象示例。 type TFruit = record color: string;
尝试创建请求与 URL 的连接。 NSMutableData 实例(responseData)也会随之被调用。当连接开始接收响应时,将在 NSMutableData 实例上调用 setLength:N
代码说明 procedure TForm1.FormCreate(Sender: TObject); var Str: string; PStr: PChar; begin Str :=
我正在尝试调整作为参数传递的某个类的数组的大小,例如 procedure Resize(MyArray: Array of TObject); begin SetLength(MyArray, 1
我正在比较这两种初始化动态数组的方法之间的性能: Arr := TArray.Create(1, 2, 3, 4, 5); 和 SetLength(Arr, 5); Arr[0] := 1; Arr[
这是代码: package vu.co.kaiyin; import java.io.FileOutputStream; import java.io.RandomAccessFile; import
我有一个动态数组myArr。当我们使用 SetLength 时,myArr 的内存中存储了什么?是“00”吗?还是未定义?在本例中, SetLength 为 myArr 分配 16 字节内存。 myA
我是一名优秀的程序员,十分优秀!