在React原生JavaScript应用程序中,如果我创建一个临时变量,而不是直接返回值,为什么Android GC行为会改变?
我觉得Android GC、JavaScriptCore或Genymotion中可能存在bug。我正在Android上测试React本机应用程序,所以我所有的代码都是用JavaScript(而不是Java)编写的。我试图找出我在以下Android模拟器上复制的崩溃:在React原生JavaScript应用程序中,如果我创建一个临时变量,而不是直接返回值,为什么Android GC行为会改变?,javascript,android,react-native,garbage-collection,Javascript,Android,React Native,Garbage Collection,我觉得Android GC、JavaScriptCore或Genymotion中可能存在bug。我正在Android上测试React本机应用程序,所以我所有的代码都是用JavaScript(而不是Java)编写的。我试图找出我在以下Android模拟器上复制的崩溃: 三星Galaxy S6-6.0.0-API 23 谷歌Nexus5x-7.1.0-API 25 我注意到我的应用程序在使用了大约5分钟后总是崩溃。在使用adb logcat查看日志后,我注意到它总是在GC运行后立即崩溃。它只是在
- 三星Galaxy S6-6.0.0-API 23
- 谷歌Nexus5x-7.1.0-API 25
WeakMap
或类似的东西。我只是将缓存的结果存储在一个普通数组中,并且我总是保存对选择器的引用,所以我认为GC不应该清除内存
我将介绍有关我的应用程序的更多详细信息。我有一个LookupTable
类,它引用一个Matrix
类。查找表预先计算了一些内容,以便更快地查找
我的查找表代码如下所示:
// @flow
import autobind from 'autobind-decorator'
export default class LookupTable {
matrix: Matrix
constructor(state) {
this.generateLookupTable(state)
}
@autobind
valueAt(x: number, y: number) {
this.matrix.get(x, y)
}
@autobind
generateLookupTable() {
// generates the Matrix at this.matrix
}
}
import Immutable from 'immutable'
import { createSelectorCreator, defaultMemoize } from 'reselect'
const createImmutableSelector = (cacheSize = 1, ...args) =>
createSelectorCreator(defaultMemoize, Immutable.is, cacheSize)(...args)
export const lookupTableSelector = createImmutableSelector(3,
firstSelector,
secondSelector,
thirdSelector,
fourthSelector,
(one, two, three, four) =>
new LookupTable(one, two, three, four))
const lookupTable = lookupTableSelector(state)
const value = lookupTable.valueAt(x, y)
我的原始选择器代码如下所示:
// @flow
import autobind from 'autobind-decorator'
export default class LookupTable {
matrix: Matrix
constructor(state) {
this.generateLookupTable(state)
}
@autobind
valueAt(x: number, y: number) {
this.matrix.get(x, y)
}
@autobind
generateLookupTable() {
// generates the Matrix at this.matrix
}
}
import Immutable from 'immutable'
import { createSelectorCreator, defaultMemoize } from 'reselect'
const createImmutableSelector = (cacheSize = 1, ...args) =>
createSelectorCreator(defaultMemoize, Immutable.is, cacheSize)(...args)
export const lookupTableSelector = createImmutableSelector(3,
firstSelector,
secondSelector,
thirdSelector,
fourthSelector,
(one, two, three, four) =>
new LookupTable(one, two, three, four))
const lookupTable = lookupTableSelector(state)
const value = lookupTable.valueAt(x, y)
如果您不熟悉reselect
或immutable js
,我只是在记忆一些计算(类似于lodash的memoize
),我使用immutable.is
检查参数相等性
最后,我会这样调用选择器:
// @flow
import autobind from 'autobind-decorator'
export default class LookupTable {
matrix: Matrix
constructor(state) {
this.generateLookupTable(state)
}
@autobind
valueAt(x: number, y: number) {
this.matrix.get(x, y)
}
@autobind
generateLookupTable() {
// generates the Matrix at this.matrix
}
}
import Immutable from 'immutable'
import { createSelectorCreator, defaultMemoize } from 'reselect'
const createImmutableSelector = (cacheSize = 1, ...args) =>
createSelectorCreator(defaultMemoize, Immutable.is, cacheSize)(...args)
export const lookupTableSelector = createImmutableSelector(3,
firstSelector,
secondSelector,
thirdSelector,
fourthSelector,
(one, two, three, four) =>
new LookupTable(one, two, three, four))
const lookupTable = lookupTableSelector(state)
const value = lookupTable.valueAt(x, y)
Android GC运行后,valueAt
导致崩溃,因为this.matrix
未定义。有趣的是,lookupTable.generateLookupTable
函数也没有定义。事实上,实例中的所有内容都是未定义的。就像选择器只是返回一个LookupTable
实例的外壳,其中所有的数据和方法都消失了
因此,以下是我尝试的解决方法:
export const lookupTableSelectorWithoutGCFix = createImmutableSelector(3,
firstSelector,
secondSelector,
thirdSelector,
fourthSelector,
(one, two, three, four) =>
new LookupTable(one, two, three, four))
export const lookupTableSelector = (gameState: Map) => {
const lookupTable = lookupTableSelectorWithoutGCFix(gameState)
if (lookupTable.matrix == null) {
console.warn('LookupTable selector returned an instance with an undefined matrix.' +
'This might be a GC bug on Android. Will clear the cache and generate a new instance.')
lookupTableSelectorWithoutGCFix.clearCache()
return lookupTableSelectorWithoutGCFix(gameState)
}
return lookupTable
}
奇怪的是,这个代码从来没有被真正调用过。我从未在adb logcat
中看到控制台警告,它也从未在模拟器中显示为黄色框。在此之前,崩溃发生在每次GC运行之后。但在这次更改之后,我通过5次GC运行测试了该应用程序,一切都很顺利。所以无论我在这里做了什么,我想它改变了安卓GC的行为,不再为我的LookupTable
实例清除内存
你能理解为什么会发生这种情况吗?或者这可能是Android GC中的引用计数错误