Skip to content

Commit d80f664

Browse files
committed
Add convenience functions for checking JVM config
After the JVM has started, it is nice to be able to easily check characteristics of the JVM from the Runtime API, including current and maximum heap sizes, as well as number of available processors. (It is also nice to be able to easily split infinitives in a commit message.) Relatedly, it can be nice to be able to call the garbage collector directly. Note that we do not expose the Runtime.getRuntime().freeMemory() method, because it can be confusing: one would naively expect freeMemory() to equal maxMemory() - usedMemory(), but in actuality it represents the amount of free memory within the bounds of the memory already reserved by the JVM *at the moment*. So it is typically not a very useful number.
1 parent 9aa2a59 commit d80f664

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

src/scyjava/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@
9696
)
9797
from scyjava._java import ( # noqa: F401
9898
JavaClasses,
99+
available_processors,
100+
gc,
99101
is_awt_initialized,
100102
is_jarray,
101103
is_jvm_headless,
@@ -107,6 +109,9 @@
107109
jstacktrace,
108110
jvm_started,
109111
jvm_version,
112+
memory_max,
113+
memory_total,
114+
memory_used,
110115
shutdown_jvm,
111116
start_jvm,
112117
when_jvm_starts,

src/scyjava/_java.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def java_import(func: Callable[[], str]) -> Callable[[], jpype.JClass]:
6666
@property
6767
def inner(self):
6868
if not jvm_started():
69-
raise Exception()
69+
raise RuntimeError("JVM has not started yet!")
7070
try:
7171
return jimport(func(self))
7272
except TypeError:
@@ -302,6 +302,80 @@ def jvm_started() -> bool:
302302
return jpype.isJVMStarted()
303303

304304

305+
def gc() -> None:
306+
"""
307+
Do a round of Java garbage collection.
308+
309+
This function is a shortcut for Java's System.gc().
310+
311+
:raise RuntimeError: if the JVM has not yet been started.
312+
"""
313+
_jc.System.gc()
314+
315+
316+
def memory_total() -> int:
317+
"""
318+
Get the total amount of memory currently reserved by the JVM.
319+
320+
This number will always be less than or equal to memory_max().
321+
322+
In case the JVM was configured with -Xms flag upon startup (e.g. using
323+
the scyjava.config.set_heap_min function), the initial value will typically
324+
correspond approximately, but not exactly, to the configured value,
325+
although it is likely to grow over time as more Java objects are allocated.
326+
327+
This function is a shortcut for Java's Runtime.getRuntime().totalMemory().
328+
329+
:return: The total memory in bytes.
330+
:raise RuntimeError: if the JVM has not yet been started.
331+
"""
332+
return int(_jc.Runtime.getRuntime().totalMemory())
333+
334+
335+
def memory_max() -> int:
336+
"""
337+
Get the maximum amount of memory that the JVM will attempt to use.
338+
339+
This number will always be greater than or equal to memory_total().
340+
341+
In case the JVM was configured with -Xmx flag upon startup (e.g. using
342+
the scyjava.config.set_heap_max function), the value will typically
343+
correspond approximately, but not exactly, to the configured value.
344+
345+
This function is a shortcut for Java's Runtime.getRuntime().maxMemory().
346+
347+
:return: The maximum memory in bytes.
348+
:raise RuntimeError: if the JVM has not yet been started.
349+
"""
350+
return int(_jc.Runtime.getRuntime().maxMemory())
351+
352+
353+
def memory_used() -> int:
354+
"""
355+
Get the amount of memory currently in use by the JVM.
356+
357+
This function is a shortcut for
358+
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory().
359+
360+
:return: The used memory in bytes.
361+
:raise RuntimeError: if the JVM has not yet been started.
362+
"""
363+
return memory_total() - int(_jc.Runtime.getRuntime().freeMemory())
364+
365+
366+
def available_processors() -> int:
367+
"""
368+
Get the number of processors available to the JVM.
369+
370+
This function is a shortcut for Java's
371+
Runtime.getRuntime().availableProcessors().
372+
373+
:return: The number of available processors.
374+
:raise RuntimeError: if the JVM has not yet been started.
375+
"""
376+
return int(_jc.Runtime.getRuntime().availableProcessors())
377+
378+
305379
def is_jvm_headless() -> bool:
306380
"""
307381
Return true iff Java is running in headless mode.
@@ -575,3 +649,15 @@ def jarray(kind, lengths: Sequence):
575649
for i in range(len(arr)):
576650
arr[i] = jarray(kind, lengths[1:])
577651
return arr
652+
653+
654+
# fmt: off
655+
class _JavaClasses(JavaClasses):
656+
@JavaClasses.java_import
657+
def Runtime(self): return "java.lang.Runtime" # noqa: E272
658+
@JavaClasses.java_import
659+
def System(self): return "java.lang.System" # noqa: E272
660+
# fmt: on
661+
662+
663+
_jc = _JavaClasses()

0 commit comments

Comments
 (0)