JavaScriptCore 框架详细解析(三) —— 内存管理与线程安全

版本记录

版本号 时间
V1.0 2017.11.05

前言

JavaScriptCore是用来评估应用程序中的JavaScript程序,并支持应用程序的JavaScript脚本编写。接下来这几篇我们就详细的解析一下JavaScriptCore框架的使用情况。感兴趣的可以看上面写的那篇。
1. JavaScriptCore 框架详细解析(一) —— 基本概要
2. JavaScriptCore 框架详细解析(二) —— JS与OC通信

内存管理

正常情况下,OC和JS对象之间内存管理都无需我们去关心。但是有几个方面需要我们注意。

1. 不要在block里面直接使用context,或者使用外部的JSValue对象

下面我们看一个错误例子。

self.context[@"block"] = ^(){
     JSValue *value = [JSValue valueWithObject:@"aaa" inContext:self.context];
};

上面的就是个错误代码,编译器就会提示你的,block里面包含self,构成循环引用,引起内存问题。下面看一个隐蔽的。

JSValue *value = [JSValue valueWithObject:@"ssss" inContext:self.context];

    self.context[@"log"] = ^(){
        NSLog(@"%@",value);
    };

这里需要说明的是引入了外面的value,value对context和其管理的JS对象均为强引用,block里面是context对JS进行强引用,构成了循环引用而泄露,context是不能销毁的。

2. OC对象不要用属性直接保存JSValue对象

//用来保存JS的对象
@property (nonatomic, strong) JSvalue *jsValue;

...

@property (nonatomic, strong) JSProtocolObj *obj;

...
//加载JS代码到context中
   [self.context evaluateScript:
   @"function callback (){};

    function setObj(obj) {
    this.obj = obj;
    obj.jsValue=callback;
}"];
...

//调用JS方法
[self.context[@"setObj"] callWithArguments:@[self.obj]];  

上面的例子调用JS方法,进行赋值,JS对象保留了传进来的obj,最后,JS将自己的回调callback赋值给了obj,方便obj下次回调给JS。由于JS那边保存了obj,而且obj这边也保留了JS的回调。这样就形成了循环引用。

下面我们就看一下如何解决这样的循环引用带来的内存问题。

解决方法就是使用JSManagedValueJSManagedValue 本身就是我们需要的弱引用。用官方的话来说叫garbage collection weak reference。但是它帮助我们持有JSValue对象必须同时满足一下两个条件。

  • The JSManagedValue's JavaScript value is reachable from JavaScript
  • The owner of the managed reference is reachable in Objective-C. Manually adding or removing the managed reference in the JSVirtualMachine determines reachability.

JSManagedValue 帮助我们保存JSValue,那里面保存的JS对象必须在JS中存在,同时 JSManagedValue 的owner在OC中也存在。我们可以通过它提供的两个方法

  • + (JSManagedValue )managedValueWithValue:(JSValue )value;
  • (JSManagedValue )managedValueWithValue:(JSValue )value andOwner:(id)owner创建JSManagedValue对象。通过JSVirtualMachine的方法- (void)addManagedReference:(id)object withOwner:(id)owner来建立这个弱引用关系。通过- (void)removeManagedReference:(id)object withOwner:(id)owner来手动移除他们之间的联系。

所以可以修改代码,如下所示。

//重写setter方法

- (void)setJsValue:(JSValue *)jsValue
{
    _managedValue = [JSManagedValue managedValueWithValue:jsValue];

    [[[JSContext currentContext] virtualMachine] addManagedReference:_managedValue 
    withOwner:self];
}

3. 不要在不同的 JSVirtualMachine 之间进行传递JS对象

一个 JSVirtualMachine可以运行多个context,由于都是在同一个堆内存和同一个垃圾回收下,所以相互之间传值是没问题的。但是如果在不同的 JSVirtualMachine传值,垃圾回收就不知道他们之间的关系了,可能会引起异常。


线程

JavaScriptCore 线程是安全的,每个context运行的时候通过lock关联的JSVirtualMachine。如果要进行并发操作,可以创建多个JSVirtualMachine实例进行操作。

后记

未完,待续~~~

参考文章

1. JavaScriptCore 使用

JavaScriptCore 框架详细解析(三) —— 内存管理与线程安全_第1张图片

你可能感兴趣的:(JavaScriptCore 框架详细解析(三) —— 内存管理与线程安全)