Skip to content

Commit

Permalink
🦄 refactor: Rewrite getV8HeapStatistics(), getV8HeapSpaceStatistics() v2
Browse files Browse the repository at this point in the history
  • Loading branch information
caoccao committed Jun 12, 2024
1 parent 1230da9 commit 363508d
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 89 deletions.
75 changes: 49 additions & 26 deletions cpp/jni/javet_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,41 @@

namespace Javet {
namespace Monitor {
struct HeapSpaceStatisticsContainer {
jobject allocationSpace;
jobject completableFuture;

HeapSpaceStatisticsContainer(JNIEnv* jniEnv, jobject completableFuture, jobject allocationSpace) noexcept {
this->allocationSpace = jniEnv->NewGlobalRef(allocationSpace);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
this->completableFuture = jniEnv->NewGlobalRef(completableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
}

~HeapSpaceStatisticsContainer() {
FETCH_JNI_ENV(GlobalJavaVM);
jniEnv->DeleteGlobalRef(allocationSpace);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
jniEnv->DeleteGlobalRef(completableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
}
};

struct HeapStatisticsContainer {
jobject completableFuture;

HeapStatisticsContainer(JNIEnv* jniEnv, jobject completableFuture) noexcept {
this->completableFuture = jniEnv->NewGlobalRef(completableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
}

~HeapStatisticsContainer() {
FETCH_JNI_ENV(GlobalJavaVM);
jniEnv->DeleteGlobalRef(completableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
}
};

void Initialize(JNIEnv* jniEnv) noexcept {
jclassV8AllocationSpace = FIND_CLASS(jniEnv, "com/caoccao/javet/enums/V8AllocationSpace");
jmethodIDV8AllocationSpaceGetIndex = jniEnv->GetMethodID(jclassV8AllocationSpace, "getIndex", "()I");
Expand Down Expand Up @@ -48,67 +83,57 @@ namespace Javet {
v8::Isolate* v8Isolate,
const jobject jAllocationSpace) noexcept {
jobject jCompletableFuture = jniEnv->NewObject(jclassCompletableFuture, jmethodIDCompletableFutureConstructor);
auto jobjectRefs = new jobject[]{ jniEnv->NewGlobalRef(jCompletableFuture), jniEnv->NewGlobalRef(jAllocationSpace) };
auto containerPointer = new HeapSpaceStatisticsContainer(jniEnv, jCompletableFuture, jAllocationSpace);
INCREASE_COUNTER(Javet::Monitor::CounterType::New);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
if (v8Isolate->IsInUse()) {
v8Isolate->RequestInterrupt(GetHeapSpaceStatisticsCallback, &jobjectRefs);
v8Isolate->RequestInterrupt(GetHeapSpaceStatisticsCallback, containerPointer);
}
else {
auto v8Locker = v8::Locker(v8Isolate);
GetHeapSpaceStatisticsCallback(v8Isolate, jobjectRefs);
GetHeapSpaceStatisticsCallback(v8Isolate, containerPointer);
}
return jCompletableFuture;
}

void GetHeapSpaceStatisticsCallback(v8::Isolate* v8Isolate, void* data) noexcept {
FETCH_JNI_ENV(GlobalJavaVM);
v8::HeapSpaceStatistics heapSpaceStatistics;
auto jobjectRefs = static_cast<jobject*>(data);
auto jCompletableFuture = jobjectRefs[0];
auto jAllocationSpace = jobjectRefs[1];
auto index = jniEnv->CallIntMethod(jAllocationSpace, jmethodIDV8AllocationSpaceGetIndex);
auto containerPointer = static_cast<HeapSpaceStatisticsContainer*>(data);
auto index = jniEnv->CallIntMethod(containerPointer->allocationSpace, jmethodIDV8AllocationSpaceGetIndex);
v8Isolate->GetHeapSpaceStatistics(&heapSpaceStatistics, static_cast<size_t>(index));
auto jHeapSpaceStatistics = jniEnv->NewObject(jclassV8HeapSpaceStatistics, jmethodIDV8HeapSpaceStatisticsConstructor,
Javet::Converter::ToJavaString(jniEnv, heapSpaceStatistics.space_name()),
static_cast<jlong>(heapSpaceStatistics.physical_space_size()),
static_cast<jlong>(heapSpaceStatistics.space_available_size()),
static_cast<jlong>(heapSpaceStatistics.space_size()),
static_cast<jlong>(heapSpaceStatistics.space_used_size()));
jniEnv->CallObjectMethod(jHeapSpaceStatistics, jmethodIDV8HeapSpaceStatisticsSetAllocationSpace, jAllocationSpace);
jniEnv->CallBooleanMethod(jCompletableFuture, jmethodIDCompletableFutureComplete, jHeapSpaceStatistics);
jniEnv->CallObjectMethod(jHeapSpaceStatistics, jmethodIDV8HeapSpaceStatisticsSetAllocationSpace, containerPointer->allocationSpace);
jniEnv->CallBooleanMethod(containerPointer->completableFuture, jmethodIDCompletableFutureComplete, jHeapSpaceStatistics);
jniEnv->DeleteLocalRef(jHeapSpaceStatistics);
jniEnv->DeleteGlobalRef(jCompletableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
jniEnv->DeleteGlobalRef(jAllocationSpace);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
delete jobjectRefs;
delete containerPointer;
INCREASE_COUNTER(Javet::Monitor::CounterType::Delete);
}

jobject GetHeapStatistics(
JNIEnv* jniEnv,
v8::Isolate* v8Isolate) noexcept {
jobject jCompletableFuture = jniEnv->NewObject(jclassCompletableFuture, jmethodIDCompletableFutureConstructor);
auto jobjectRefs = new jobject[]{ jniEnv->NewGlobalRef(jCompletableFuture) };
auto containerPointer = new HeapStatisticsContainer(jniEnv, jCompletableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::New);
INCREASE_COUNTER(Javet::Monitor::CounterType::NewGlobalRef);
if (v8Isolate->IsInUse()) {
v8Isolate->RequestInterrupt(GetHeapStatisticsCallback, jobjectRefs);
v8Isolate->RequestInterrupt(GetHeapStatisticsCallback, containerPointer);
}
else {
auto v8Locker = v8::Locker(v8Isolate);
GetHeapStatisticsCallback(v8Isolate, jobjectRefs);
GetHeapStatisticsCallback(v8Isolate, containerPointer);
}
return jCompletableFuture;
}

void GetHeapStatisticsCallback(v8::Isolate* v8Isolate, void* data) noexcept {
FETCH_JNI_ENV(GlobalJavaVM);
v8::HeapStatistics heapStatistics;
auto jobjectRefs = static_cast<jobject*>(data);
auto jCompletableFuture = jobjectRefs[0];
auto containerPointer = static_cast<HeapStatisticsContainer*>(data);
v8Isolate->GetHeapStatistics(&heapStatistics);
auto jHeapStatistics = jniEnv->NewObject(jclassV8HeapStatistics, jmethodIDV8HeapStatisticsConstructor,
static_cast<jlong>(heapStatistics.does_zap_garbage()),
Expand All @@ -125,11 +150,9 @@ namespace Javet {
static_cast<jlong>(heapStatistics.total_physical_size()),
static_cast<jlong>(heapStatistics.used_global_handles_size()),
static_cast<jlong>(heapStatistics.used_heap_size()));
jniEnv->CallBooleanMethod(jCompletableFuture, jmethodIDCompletableFutureComplete, jHeapStatistics);
jniEnv->CallBooleanMethod(containerPointer->completableFuture, jmethodIDCompletableFutureComplete, jHeapStatistics);
jniEnv->DeleteLocalRef(jHeapStatistics);
jniEnv->DeleteGlobalRef(jCompletableFuture);
INCREASE_COUNTER(Javet::Monitor::CounterType::DeleteGlobalRef);
delete jobjectRefs;
delete containerPointer;
INCREASE_COUNTER(Javet::Monitor::CounterType::Delete);
}

Expand Down
3 changes: 2 additions & 1 deletion docs/reference/resource_management/memory_management.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,5 @@ V8 exposes quite a few statistics for applications to analyze the memory usage,

.. note::

More statistics will be exposed in new releases. Please file issues if you need more of them.
* If the ``V8Runtime`` is in use, calling ``getV8HeapSpaceStatistics()`` and ``getV8HeapStatistics()`` may take a slight chance (a race condition) to have tiny memory leak. Please refer to this `issue <https://issues.chromium.org/issues/345822325>`_ for details. It's recommended to call them when the ``V8Runtime`` is idle.
* More statistics will be exposed in new releases. Please file issues if you need more of them.
1 change: 1 addition & 0 deletions docs/release_notes/release_notes_3_1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Release Notes 3.1.x
--------------

* Rewrote ``getV8HeapStatistics()``, ``getV8HeapSpaceStatistics()`` for ``V8Runtime`` to remediate the racing condition
* Added ``observerTimeoutMillis`` to ``JavetEngineConfig``

3.1.3 V8 v12.6
--------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.caoccao.javet.enums.V8AllocationSpace;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.interfaces.IJavetClosable;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;
import com.caoccao.javet.interop.engine.observers.*;
import com.caoccao.javet.interop.monitoring.V8HeapSpaceStatistics;
Expand Down Expand Up @@ -77,7 +76,9 @@ default int getAverageReferenceCount() {
*/
default V8HeapSpaceStatistics getAverageV8HeapSpaceStatistics(final V8AllocationSpace v8AllocationSpace) {
V8RuntimeObserverAverageV8HeapSpaceStatistics observer = new V8RuntimeObserverAverageV8HeapSpaceStatistics(
v8AllocationSpace, getConfig().getPoolMaxSize());
v8AllocationSpace,
getConfig().getPoolMaxSize(),
getConfig().getObserverTimeoutMillis());
observe(observer);
return observer.getResult();
}
Expand All @@ -90,7 +91,8 @@ default V8HeapSpaceStatistics getAverageV8HeapSpaceStatistics(final V8Allocation
*/
default V8HeapStatistics getAverageV8HeapStatistics() {
V8RuntimeObserverAverageV8HeapStatistics observer = new V8RuntimeObserverAverageV8HeapStatistics(
getConfig().getPoolMaxSize());
getConfig().getPoolMaxSize(),
getConfig().getObserverTimeoutMillis());
observe(observer);
return observer.getResult();
}
Expand Down
Loading

1 comment on commit 363508d

@caoccao
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's for #350

Please sign in to comment.