Kernel32.INSTANCE.ReadProcessMemory JNA 真的很慢
Kernel32.INSTANCE.ReadProcessMemory REALLY Slow In JNA
我正在编写一个游戏 hack,它使用内存操作来工作,并决定在 Java 中针对 FUD 方面进行操作(几乎可以立即检测到本机 hack)。
我有这个方法可以从 windows 调用 ReadProcessMemory
中读取内存对象
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
Memory output = new Memory(bytesToRead);
有时需要大约 0-5+ms 来执行
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
也需要大约 0-5+ms 来执行。
读取这个的程序每个周期调用这些方法大约 1k 次(16ms 周期)。
编辑:我写了一个基本测试 class 来测试 5000 次调用需要多长时间
public final class Test {
public static final int AMOUNT_OF_CALLS = 5000;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
for (int i = 0; i < AMOUNT_OF_CALLS; i++) {
Memory m = readMemory(new Pointer(1), 0xFFFFFFF, ThreadLocalRandom.current().nextInt(1, 8)); //Random between a byte read, or long
m.dispose();
}
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms todo " + AMOUNT_OF_CALLS + " readMemory calls.");
}
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
Kernel32.INSTANCE.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
}
是否有任何其他方法可以执行 readMemory 方法,以便执行所有 5000 次调用所需的时间少于 32 毫秒?
首先,我总是在 C/C++ 中编写内存处理。但是如果你需要在 Java 中进行,我会考虑创建一个内存实例并将其作为参数传递,这将避免堆 construction/disposal 例程。
类似于:
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
final Memory output = new Memory(8);
for (int i = 0; i < AMOUNT_OF_CALLS; i++) {
Memory m = readMemory(new Pointer(1), 0xFFFFFFF, ThreadLocalRandom.current().nextInt(1, 8), memory); //Random between a byte read, or long
}
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms todo " + AMOUNT_OF_CALLS + " readMemory calls.");
}
public static Memory readMemory(Pointer process, long address, int bytesToRead, final Memory output) {
output.setSize( bytesToRead ) ;
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
类似的东西 - 不确定您是否有权修改内存大小,但理想情况下它可以创建可容纳所有结果的存储空间,并且您可以为每次调用设置实际存储的数量。这应该避免昂贵的堆工作。
您想在 32 毫秒内完成 5000 次调用。每次调用大约需要 6us。您可以使用纯 C
代码(不涉及 Java)做到这一点吗?你能在原始 JNI 中做到这一点吗?如果不是,那么尝试让它与 JNA 一起工作就没有多大意义。您不仅需要进行数据传输,还需要一些时间来处理该数据。
Memory
只是 Java 表示在 GC 上释放的 malloc
内存块。预分配您需要的不同块的数量,或创建一个直接的 NIO 缓冲区(这可能允许更有效地调整本机后备内存)。
预分配后,确保您使用的是直接映射,然后再次分析以查看您将时间花在哪里。
public class MyKernel32 {
static { Native.register(NativeLibrary.getInstance("kernel32", W32APIOptions.DEFAULT_OPTIONS)); }
public static native long ReadProcessMemory(HANDLE process, long address, Pointer buffer, int size, IntByReference numRead);
}
您 可能 通过使用 long
代替 Pointer
获得一些收益,但是 YMMV,并且始终衡量增加的复杂性的影响。
我正在编写一个游戏 hack,它使用内存操作来工作,并决定在 Java 中针对 FUD 方面进行操作(几乎可以立即检测到本机 hack)。
我有这个方法可以从 windows 调用 ReadProcessMemory
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
Memory output = new Memory(bytesToRead);
有时需要大约 0-5+ms 来执行
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
也需要大约 0-5+ms 来执行。
读取这个的程序每个周期调用这些方法大约 1k 次(16ms 周期)。
编辑:我写了一个基本测试 class 来测试 5000 次调用需要多长时间
public final class Test {
public static final int AMOUNT_OF_CALLS = 5000;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
for (int i = 0; i < AMOUNT_OF_CALLS; i++) {
Memory m = readMemory(new Pointer(1), 0xFFFFFFF, ThreadLocalRandom.current().nextInt(1, 8)); //Random between a byte read, or long
m.dispose();
}
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms todo " + AMOUNT_OF_CALLS + " readMemory calls.");
}
public static Memory readMemory(Pointer process, long address, int bytesToRead) {
Memory output = new Memory(bytesToRead);
Kernel32.INSTANCE.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
}
是否有任何其他方法可以执行 readMemory 方法,以便执行所有 5000 次调用所需的时间少于 32 毫秒?
首先,我总是在 C/C++ 中编写内存处理。但是如果你需要在 Java 中进行,我会考虑创建一个内存实例并将其作为参数传递,这将避免堆 construction/disposal 例程。
类似于:
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
final Memory output = new Memory(8);
for (int i = 0; i < AMOUNT_OF_CALLS; i++) {
Memory m = readMemory(new Pointer(1), 0xFFFFFFF, ThreadLocalRandom.current().nextInt(1, 8), memory); //Random between a byte read, or long
}
System.out.println("Took " + (System.currentTimeMillis() - start) + "ms todo " + AMOUNT_OF_CALLS + " readMemory calls.");
}
public static Memory readMemory(Pointer process, long address, int bytesToRead, final Memory output) {
output.setSize( bytesToRead ) ;
KERNEL32.ReadProcessMemory(process, address, output, bytesToRead, 0);
return output;
}
类似的东西 - 不确定您是否有权修改内存大小,但理想情况下它可以创建可容纳所有结果的存储空间,并且您可以为每次调用设置实际存储的数量。这应该避免昂贵的堆工作。
您想在 32 毫秒内完成 5000 次调用。每次调用大约需要 6us。您可以使用纯 C
代码(不涉及 Java)做到这一点吗?你能在原始 JNI 中做到这一点吗?如果不是,那么尝试让它与 JNA 一起工作就没有多大意义。您不仅需要进行数据传输,还需要一些时间来处理该数据。
Memory
只是 Java 表示在 GC 上释放的 malloc
内存块。预分配您需要的不同块的数量,或创建一个直接的 NIO 缓冲区(这可能允许更有效地调整本机后备内存)。
预分配后,确保您使用的是直接映射,然后再次分析以查看您将时间花在哪里。
public class MyKernel32 {
static { Native.register(NativeLibrary.getInstance("kernel32", W32APIOptions.DEFAULT_OPTIONS)); }
public static native long ReadProcessMemory(HANDLE process, long address, Pointer buffer, int size, IntByReference numRead);
}
您 可能 通过使用 long
代替 Pointer
获得一些收益,但是 YMMV,并且始终衡量增加的复杂性的影响。