caoccao/Javet

V8 module(s) not recycled and V8 object(s) not recycled

Closed this issue · 5 comments

image

app/src/main/assets/js/sampledata/tasks/task_dy_toker.js

import { C270301 } from "version/27.3.0.js";

app/src/main/assets/js/sampledata/version/27.3.0.js

export const C290701 = {}

package top.deeke.script;

import android.content.Context;
import android.util.Log;

import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import com.caoccao.javet.exceptions.JavetCompilationException;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.exceptions.JavetExecutionException;
import com.caoccao.javet.exceptions.JavetScriptingError;
import com.caoccao.javet.exceptions.JavetTerminatedException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import top.deeke.script.func.Asset;
import top.deeke.script.js.V8.V8Manager;

@RunWith(AndroidJUnit4.class)
public class JavetInstrumentedTest {
@rule
public ActivityScenarioRule activityRule = new ActivityScenarioRule<>(ScriptActivity.class);

private void loadModules(V8Runtime v8Runtime, Context context) {
    v8Runtime.setV8ModuleResolver((runtime, resourceName, v8ModuleReferrer) -> {
        Log.d("debug", resourceName + ":::" + v8Runtime);
        try {
            V8Manager.setType(1);
            return runtime.getExecutor(V8Manager.getFileContent(context, resourceName)).setResourceName(resourceName).compileV8Module();
        } catch (JavetCompilationException | JavetExecutionException | IOException e) {
            throw new RuntimeException(e);
        }
    });
}

public String getFileContent(Context context, String filename) throws IOException {
    return Asset.readFile(context, "js/sampledata/" + filename);
}

private static void closeByException(V8Runtime v8Runtime) {
    try {
        v8Runtime.removeV8Modules();//移除自定义的所有js模块
        Log.d("debug", "模块清理完成");
        java.lang.System.gc();
        java.lang.System.runFinalization();
        v8Runtime.lowMemoryNotification();
        v8Runtime.close();
        Log.d("debug", "成功关闭了哦");
    } catch (JavetException e) {
        Log.d("debug", "停止错误:" + e.getMessage());
    }
}

@Test
public void recycleBug() {
    Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
    ActivityScenario<ScriptActivity> scenario = activityRule.getScenario();

    scenario.onActivity(activity -> {
        Path filePath = Paths.get("tasks/task_dy_toker.js");
        V8Runtime v8Runtime = null;
        try {
            v8Runtime = V8Host.getV8Instance().createV8Runtime();
            loadModules(v8Runtime, appContext);

            try {
                v8Runtime.getExecutor(getFileContent(appContext, filePath.toString())).setModule(true).setResourceName(filePath.toString()).executeVoid();
            } catch (IOException err) {
                Log.d("debug", "错误:" + err);
            }
        } catch (JavetTerminatedException e) {
            Log.d("debug", "打断了:" + e.getMessage());
        } catch (JavetExecutionException | JavetCompilationException e) {
            JavetScriptingError err = e.getScriptingError();
            Log.d("debug", "错误:" + err.toString());
        } catch (JavetException er) {
            Log.d("debug", "运行错误:" + Objects.requireNonNull(er.getMessage()));
        } finally {
            Log.d("debug", "中断了:");
            closeByException(v8Runtime);
        }
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    });
}

}

Could you please create a repo that reproduces the issue? I don't think it's related to Android development.

Could you please create a repo that reproduces the issue? I don't think it's related to Android development.

package top.deeke.script;//package top.deeke.script;

import com.caoccao.javet.exceptions.JavetCompilationException;
import com.caoccao.javet.exceptions.JavetException;
import com.caoccao.javet.exceptions.JavetExecutionException;
import com.caoccao.javet.interop.V8Host;
import com.caoccao.javet.interop.V8Runtime;

import org.junit.Test;

import java.io.IOException;

public class JavetUnit2Test {
    private void loadModules(V8Runtime v8Runtime) {
        v8Runtime.setV8ModuleResolver((runtime, resourceName, v8ModuleReferrer) -> {
            try {
                return runtime.getExecutor(getFileContent(resourceName)).setResourceName(resourceName).compileV8Module();
            } catch (JavetCompilationException | JavetExecutionException | IOException e) {
                throw new RuntimeException(e);
            }
        });
    }

    public String getFileContent(String filename) throws IOException {
        return "export const Dy = {name: 'my name'}";//这里的逻辑写死
    }

    @Test
    public void recycleBug() {
        V8Runtime v8Runtime = null;
        try {
            v8Runtime = V8Host.getV8Instance().createV8Runtime();
            loadModules(v8Runtime);
            v8Runtime.getExecutor("import {Dy} from 'dy.js';Dy.name;").setModule(true).setResourceName("main.js").executeVoid();
        } catch (JavetException ignored) {

        } finally {
            assert v8Runtime != null;
            try {
                v8Runtime.removeV8Modules();//移除自定义的所有js模块
                System.gc();
                System.runFinalization();
                v8Runtime.lowMemoryNotification();
                v8Runtime.close();
            } catch (JavetException ignored) {

            }
        }
    }
}

I'm expecting a github repo that I could check out and reproduce. The code you left is incomplete.

https://github.com/DeekeScript/javetTest

please pull this project and execute the unit testing inside

 List<V8Module> modules = new ArrayList<>();
  private void loadModules(V8Runtime v8Runtime) {
  v8Runtime.setV8ModuleResolver((runtime, resourceName, v8ModuleReferrer) -> {
      try {
          V8Module v8Module = runtime.getExecutor(getFileContent(resourceName)).setResourceName(resourceName).compileV8Module();
          modules.add(v8Module);
          return v8Module;
      } catch (JavetCompilationException | JavetExecutionException | IOException e) {
          throw new RuntimeException(e);
      }
  });
}

I have found a solution to the problem. When loading the module, record it in the array. Before closing v8, just close the module

for(V8Module v8Module:this.modules){
    v8Module.close();
}

System.gc();
System.runFinalization();
v8Runtime.lowMemoryNotification();