Skip to content

Commit 2616b0b

Browse files
committed
* Enhance Pointer.physicalBytes() by excluding shared pages from memory-mapped files, etc (issue #468)
1 parent 8736a12 commit 2616b0b

File tree

4 files changed

+59
-12
lines changed

4 files changed

+59
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11

2+
* Enhance `Pointer.physicalBytes()` by excluding shared pages from memory-mapped files, etc ([issue #468](https://github.com/bytedeco/javacpp/issues/468))
23
* Fix `Parser` not correctly encoding files of top-level classes produced with `@Properties(target=..., global=...)`
34
* Add `Pointer.interruptDeallocatorThread()` method to make JavaCPP classes eligible for GC ([discussion bytedeco/javacpp-presets#1115](https://github.com/bytedeco/javacpp-presets/discussions/1115))
45
* Let `Parser` output the content of `Info.javaText` in the case of `FunctionPointer` as well

src/main/java/org/bytedeco/javacpp/Pointer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,8 @@ public static long maxPhysicalBytes() {
572572
/** Makes sure to return freed memory to the system, as required by Linux, at least. */
573573
@Name("JavaCPP_trimMemory") private static native boolean trimMemory();
574574

575-
/** Returns the amount of physical memory currently used by the whole process, or 0 if unknown.
576-
* Also known as "resident set size" (Linux, Mac OS X, etc) or "working set size" (Windows). */
575+
/** Returns the amount of non-shared physical memory currently used by the whole process, or 0 if unknown.
576+
* Also known as "anonymous resident set size" (Linux, Mac OS X, etc) or "private working set size" (Windows). */
577577
@Name("JavaCPP_physicalBytes") public static native long physicalBytes();
578578

579579
/** Returns the amount of physical memory installed according to the operating system, or 0 if unknown.

src/main/java/org/bytedeco/javacpp/tools/Generator.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2011-2021 Samuel Audet
2+
* Copyright (C) 2011-2022 Samuel Audet
33
*
44
* Licensed either under the Apache License, Version 2.0, or (at your option)
55
* under the terms of the GNU General Public License as published by
@@ -552,21 +552,38 @@ boolean classes(boolean handleExceptions, boolean defineAdapters, boolean conver
552552
out.println(" char* s;");
553553
out.println(" int n;");
554554
out.println(" if ((n = pread(fd, line, sizeof(line), 0)) > 0 && (s = (char*)memchr(line, ' ', n)) != NULL) {");
555-
out.println(" size = (jlong)(atoll(s + 1) * getpagesize());");
555+
out.println(" size = (jlong)atoll(s + 1);");
556+
out.println(" if ((s = (char*)memchr(s + 1, ' ', n)) != NULL) {");
557+
out.println(" size -= (jlong)atoll(s + 1);");
558+
out.println(" }");
556559
out.println(" }");
560+
out.println(" size *= (jlong)getpagesize();");
557561
out.println(" // no close(fd);");
558562
out.println(" }");
559563
out.println("#elif defined(__APPLE__)");
560-
out.println(" task_basic_info info;");
561-
out.println(" mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;");
562-
out.println(" if (task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) {");
563-
out.println(" size = (jlong)info.resident_size;");
564+
out.println(" task_vm_info_data_t info;");
565+
out.println(" mach_msg_type_number_t count = TASK_VM_INFO_COUNT;");
566+
out.println(" if (task_info(current_task(), TASK_VM_INFO, (task_info_t)&info, &count) == KERN_SUCCESS) {");
567+
out.println(" size = (jlong)info.internal;");
564568
out.println(" }");
565569
out.println("#elif defined(_WIN32)");
566-
out.println(" PROCESS_MEMORY_COUNTERS counters;");
567-
out.println(" if (GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) {");
568-
out.println(" size = (jlong)counters.WorkingSetSize;");
570+
out.println(" DWORD length = sizeof(PSAPI_WORKING_SET_INFORMATION);");
571+
out.println(" PSAPI_WORKING_SET_INFORMATION *info = (PSAPI_WORKING_SET_INFORMATION*)malloc(length);");
572+
out.println(" BOOL success = QueryWorkingSet(GetCurrentProcess(), info, length);");
573+
out.println(" while (!success && GetLastError() == ERROR_BAD_LENGTH) {");
574+
out.println(" length = sizeof(PSAPI_WORKING_SET_INFORMATION) + info->NumberOfEntries * sizeof(PSAPI_WORKING_SET_BLOCK);");
575+
out.println(" info = (PSAPI_WORKING_SET_INFORMATION*)realloc(info, length);");
576+
out.println(" success = QueryWorkingSet(GetCurrentProcess(), info, length);");
569577
out.println(" }");
578+
out.println(" if (success && info != NULL) {");
579+
out.println(" for (DWORD i = 0; i < info->NumberOfEntries; i++) {");
580+
out.println(" size += !info->WorkingSetInfo[i].Shared;");
581+
out.println(" }");
582+
out.println(" }");
583+
out.println(" SYSTEM_INFO sysinfo;");
584+
out.println(" GetSystemInfo(&sysinfo);");
585+
out.println(" size *= (jlong)sysinfo.dwPageSize;");
586+
out.println(" free(info);");
570587
out.println("#endif");
571588
out.println(" return size;");
572589
out.println("}");

src/test/java/org/bytedeco/javacpp/PointerTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2016-2021 Samuel Audet
2+
* Copyright (C) 2016-2022 Samuel Audet
33
*
44
* Licensed either under the Apache License, Version 2.0, or (at your option)
55
* under the terms of the GNU General Public License as published by
@@ -29,7 +29,12 @@
2929
import java.nio.FloatBuffer;
3030
import java.nio.IntBuffer;
3131
import java.nio.LongBuffer;
32+
import java.nio.MappedByteBuffer;
3233
import java.nio.ShortBuffer;
34+
import java.nio.channels.FileChannel;
35+
import java.nio.file.Files;
36+
import java.nio.file.Path;
37+
import java.nio.file.StandardOpenOption;
3338
import java.util.concurrent.ExecutorService;
3439
import java.util.concurrent.Executors;
3540
import java.util.concurrent.TimeUnit;
@@ -1145,4 +1150,28 @@ static class TestFunction extends FunctionPointer {
11451150
System.out.println(e);
11461151
}
11471152
}
1153+
1154+
@Test public void testNoFileBytes() throws Exception {
1155+
System.out.println("NoFileBytes");
1156+
1157+
System.gc();
1158+
Thread.sleep(100);
1159+
long bytesBefore = Pointer.physicalBytes();
1160+
1161+
Path file = Files.createTempFile("javacpp", "tmp");
1162+
FileChannel channel = FileChannel.open(file,
1163+
StandardOpenOption.CREATE, StandardOpenOption.DELETE_ON_CLOSE,
1164+
StandardOpenOption.READ, StandardOpenOption.WRITE);
1165+
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 100_000_000);
1166+
for (int i = 0; i < 100_000_000; i++) {
1167+
buffer.put(i, (byte)i);
1168+
}
1169+
1170+
System.gc();
1171+
Thread.sleep(100);
1172+
long bytesAfter = Pointer.physicalBytes();
1173+
1174+
System.out.println(bytesBefore + " " + bytesAfter);
1175+
assertTrue(Math.abs(bytesAfter - bytesBefore) < 10_000_000 + buffer.get(0));
1176+
}
11481177
}

0 commit comments

Comments
 (0)