Skip to content

Commit

Permalink
fix: assertion "p->ref_count > 0" failed
Browse files Browse the repository at this point in the history
  • Loading branch information
HarlonWang committed Feb 6, 2022
1 parent 963e963 commit 6c93c85
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public class QuickJSTest {

@Test
public void createQuickJSContextTest() {
QuickJSContext.create();
QuickJSContext context = QuickJSContext.create();
context.destroyContext();
}

@Test
Expand All @@ -34,6 +35,8 @@ public void evalReturnTypeTest() {
assertEquals(123, context.evaluate("123;"));
assertEquals(1.23, context.evaluate("1.23;"));
assertEquals("hello wrapper", context.evaluate("\"hello wrapper\";"));

context.destroyContext();
}

@Test
Expand All @@ -54,6 +57,8 @@ public void getPropertiesTest() {
assertEquals(true, globalObject.getProperty("booleanValue"));
JSFunction function = (JSFunction) globalObject.getProperty("testFunc");
assertEquals("hello, yonglan-whl", function.call("yonglan-whl"));

context.destroyContext();
}

@Test
Expand All @@ -65,6 +70,8 @@ public void getJSArrayTest() {
"\n" +
"test(3);");
assertEquals(3, ret.get(2));

context.destroyContext();
}

@Test
Expand All @@ -76,6 +83,8 @@ public void JSFunctionArgsTest() {
JSObject globalObject = context.getGlobalObject();
JSFunction func = (JSFunction) globalObject.getProperty("test");
assertEquals("hello, 1string123.11true", func.call(1, "string", 123.11, true));

context.destroyContext();
}

@Test
Expand All @@ -87,6 +96,8 @@ public void JSFunctionNullArgsTest() {
JSObject globalObject = context.getGlobalObject();
JSFunction func = (JSFunction) globalObject.getProperty("test");
assertEquals("hello, undefined-13", func.call(null, -1, 3));

context.destroyContext();
}

@Test
Expand All @@ -104,6 +115,7 @@ public void JSFunctionArgsTestWithUnSupportType() {
assertTrue(e.toString().contains("Unsupported Java type"));
}

context.destroyContext();
}

@Test
Expand Down Expand Up @@ -149,6 +161,8 @@ public Object call(Object... args) {
});

context.evaluate("console.log(123)");

context.destroyContext();
}

@Test
Expand Down Expand Up @@ -190,6 +204,8 @@ public Object call(Object... args) {
JSObject jsObj = (JSObject) context.evaluate("render();");
JSFunction jsFunction = (JSFunction) jsObj.getProperty("func");
jsFunction.call();

context.destroyContext();
}

@Test
Expand All @@ -199,6 +215,7 @@ public void setPropertyWithJSObjectTest() {
context.getGlobalObject().setProperty("test1", context.getGlobalObject().getProperty("test"));

assertEquals("{\"count\":0}", context.getGlobalObject().getJSObjectProperty("test1").stringify());
context.destroyContext();
}

@Test
Expand All @@ -209,6 +226,42 @@ public void jsonParseTest() {
JSObject result = context.parseJSON(text);
assertEquals("270", result.getProperty("leadsId"));

context.getGlobalObject().setProperty("test", result);
Log.d("__quickjs__", "123------------------" + context.getGlobalObject().getJSObjectProperty("test").stringify());


context.destroyContext();
}

@Test
public void jsonParseTest2() {
String text = "{\"phoneNumber\":\"呼叫 18505815627\",\"leadsId\":\"270\",\"leadsBizId\":\"xxx\",\"options\":[{\"type\":\"aliyun\",\"avatarUrl\":\"https://gw.alicdn.com/tfs/TB1BYz0vpYqK1RjSZLeXXbXppXa-187-187.png\",\"personName\":\"老板\",\"storeName\":\"小店名称\",\"title\":\"智能办公电话\",\"content\":\"免费拨打\"},{\"type\":\"direct\",\"title\":\"普通电话\",\"content\":\"运营商拨打\"}]}\n";

QuickJSContext context = QuickJSContext.create();
JSFunction log = (JSFunction) context.evaluate("console.log");
JSObject jsonObj = context.parseJSON(text);
log.call(jsonObj);

context.destroyContext();
}

@Test
public void jsonParseTest3() {
String text = "{\"phoneNumber\":\"呼叫 18505815627\",\"leadsId\":\"270\",\"leadsBizId\":\"xxx\",\"options\":[{\"type\":\"aliyun\",\"avatarUrl\":\"https://gw.alicdn.com/tfs/TB1BYz0vpYqK1RjSZLeXXbXppXa-187-187.png\",\"personName\":\"老板\",\"storeName\":\"小店名称\",\"title\":\"智能办公电话\",\"content\":\"免费拨打\"},{\"type\":\"direct\",\"title\":\"普通电话\",\"content\":\"运营商拨打\"}]}\n";
QuickJSContext context = QuickJSContext.create();
JSObject a = (JSObject) context.evaluate("var a = {}; a;");
a.setProperty("test", context.parseJSON(text));
context.evaluate("console.log(a.test.leadsId);");
context.destroyContext();
}

@Test
public void jsonParseTest4() {
String text = "{\"phoneNumber\":\"呼叫 18505815627\",\"leadsId\":\"270\",\"leadsBizId\":\"xxx\",\"options\":[{\"type\":\"aliyun\",\"avatarUrl\":\"https://gw.alicdn.com/tfs/TB1BYz0vpYqK1RjSZLeXXbXppXa-187-187.png\",\"personName\":\"老板\",\"storeName\":\"小店名称\",\"title\":\"智能办公电话\",\"content\":\"免费拨打\"},{\"type\":\"direct\",\"title\":\"普通电话\",\"content\":\"运营商拨打\"}]}\n";
QuickJSContext context = QuickJSContext.create();
JSObject a = (JSObject) context.evaluate("var a = {b: {}}; a;");
a.getJSObjectProperty("b").setProperty("test", context.parseJSON(text));
context.evaluate("console.log(a.b.test.leadsId);");
context.destroyContext();
}

Expand Down Expand Up @@ -249,6 +302,8 @@ public void testGetOwnPropertyNames() {
assertEquals("ff", item);
}
}

context.destroyContext();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ public Object getProperty(JSObject jsObj, String name) {

public void setProperty(JSObject jsObj, String name, Object value) {
setProperty(context, jsObj.getPointer(), name, value);

// Value 为 JSObject 类型,需要手动增加引用计数,不然 QuickJS 垃圾回收会报
// assertion "p->ref_count > 0" 的错误。
if (value instanceof JSObject) {
((JSObject) value).dupValue();
}
}

public void freeValue(JSObject jsObj) {
Expand Down Expand Up @@ -104,6 +110,11 @@ Object call(JSObject func, long objPointer, Object... args) {
return obj;
}

/**
* Automatically manage the release of objects,
* the hold method is equivalent to call the
* dupValue and freeDupValue methods with NativeCleaner.
*/
public void hold(JSObject jsObj) {
jsObj.dupValue();
nativeCleaner.register(jsObj, jsObj.getPointer());
Expand Down
21 changes: 20 additions & 1 deletion remarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,23 @@
- globalObject 的引用计数默认是 2,暂时未弄清楚具体逻辑,目前的释放逻辑是每次 getGlobalObject 后都会 Free 下。待后续优化

- String/Atom 内存泄漏问题:虽然调用了 JSCString 的释放方法,但是因为其所在的对象是 GlobalObject,无法被释放,导致一直会被持有,这里需要进一步优化.
- String/Atom 内存泄漏问题:虽然调用了 JSCString 的释放方法,但是因为其所在的对象是 GlobalObject,无法被释放,导致一直会被持有,这里需要进一步优化.

- `void gc_decref_child(JSRuntime *, JSGCObjectHeader *): assertion "p->ref_count > 0" failed`
- 原因:某个对象引用计数为未加一,导致减一的时候校验失败
- 排查方式:先打印出 `gc_decref_child``p->ref_count <= 0` 的对象信息,因为执行到方法时,对象一般已经释放,会显示为 `null`,但是可以看到指针信息,可以选择以下任一方式定位到具体对象信息
- 方式1:打开 `quickjs.c` 里的 DUMP_FREE 开关,打印出所有的 `free` 对象,然后指针去匹配查找到释放前的对象信息
- 方式2:找到 `__JS_FreeValueRT` 方法,并注释以下代码,不释放对象,这样在 `gc_decref_child` 里就可以看到对象的具体信息。


case JS_TAG_OBJECT:
case JS_TAG_FUNCTION_BYTECODE:
{
// JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);
// if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {
// list_del(&p->link);
// list_add(&p->link, &rt->gc_zero_ref_count_list);
// if (rt->gc_phase == JS_GC_PHASE_NONE) {
// free_zero_refcount(rt);
// }
// }

0 comments on commit 6c93c85

Please sign in to comment.