我的React-Native应用程序中有一个奇怪的内存泄漏。这是一个不变的RAM增长。我的状态被规范化,然后转换为不可变状态。有一个套接字处理程序可以更新状态中的现有对象。这会导致RAM在新消息更新状态时缓慢增加。
州:
const state = {
entities: {
2000: {
1: {
id: 1,
name: "I am normalized",
coordinates:[
{
lat: 0,
lng: 0
}
]
},
2: {
id: 2,
name: "me too",
coordinates:[
{
lat: 0,
lng: 0
}
]
}
},
1337: {
2: {
id: 2,
name: "me too",
coordinates:[
{
lat: 0,
lng: 0
}
]
},
3: {
id: 3,
name: "also normalized",
coordinates:[
{
lat: 0,
lng: 0
}
]
}
}
},
results: {
2000: [1,2],
1337: [2,3]
},
};
然后用fromJS()
将其转换为不可变状态。
我有一个套接字处理程序,它将action.payload
传递给reducer。
action = {
payload: {
message_type: COORDINATES_UPDATE,
messages: [
{
id: 1,
coordinates: [
{
lat: 180,
lng: 180
}
]
},
{
id: 2,
coordinates: [
{
lat: 90,
lng: 90
}
]
}
]
}
}
处理传入操作的reducer:
case SOCKET_MESSAGE: {
let newState = state;
if(action.payload.message_type == "COORDINATES_UPDATE") {
action.payload.messages.map((incoming_message) => {
let id = incoming_message.id;
let coordinates = incoming_message.coordinates;
newState.get("results").map((data, entities_id) => {
if(data.indexOf(id) > -1) {
newState = newState.setIn(["entities", entities_id, "" + id, "coordinates"], fromJS(coordinates));
}
})
})
return newState;
}
}
这会在results
Map()
中搜索现有的id
,如果确实存在,则更新实体对象。据我所知,这个逻辑没有问题,状态正确更新并反映在render()
组件中,尽管出于调试目的,我将渲染空<View />
作为我的整个应用程序,并且只更新状态。
然而,每个setIn
或updateIn
都会略微增加RAM,并且随着更新的频率,我会在几分钟内增长到GB。
相关套餐:
"react": "16.0.0",
"react-native": "0.50.3",
"immutable": "^3.8.2",
"normalizr": "^3.2.4",
"redux": "^3.7.2",
哦,那是一个巨大的;)你应该检查两件事:
0)你有多少个插座连接?您可能有5-10并且所有数据都成倍增加
1)你使用redux-dev-tool吗?在您的情况下,它可能会占用大量内存,请考虑停用以进行生产/测试
Normalizr最初是为浏览器开发的。实体的内存消耗问题是众所周知的,然而,实际上它并未被视为障碍,因为浏览器上的页面生命周期足够短。
Best practices to handle memory consumption of normalized data · Issue #47 · paularmstrong/normalizr
同时,在本机应用程序中,必须正确释放内存。不幸的是,目前没有优雅的图书馆或解决方案。妥协计划:
我最终尝试了这个线程和github的许多不同的解决方案,但最耗时(和悲伤)的解决方案最好。取出ImmutableJS。
用lodash函数替换后,内存稳定。
const newState = state; //just because i don't want to mutate state
let updates = {}; //put my updates here
return _.merge({}, newState, updates); //merge into an empty object
reselect
期望每次状态变异时都有一个新对象,并且我有一个非常嵌套的状态结构。因此我选择了_.merge({}, ...)
而不是_.assign
仍然有一个非常小的增长,但这比以前更好。