在iOS应用程序中输入背景时将图像的新副本加载到内存中
我已经创建了一个全新的React原生项目(v0.60.4),并在真正的iPhone11Pro iOS 13.1.3上以发布模式运行它。app.js非常简单:在iOS应用程序中输入背景时将图像的新副本加载到内存中,ios,react-native,Ios,React Native,我已经创建了一个全新的React原生项目(v0.60.4),并在真正的iPhone11Pro iOS 13.1.3上以发布模式运行它。app.js非常简单: 从“React”导入React; 进口{ 安全区域视图, 形象,, }从“反应本机”; 常量应用程序:()=>React$Node=()=>{ 返回( ); }; 导出默认应用程序; 我注意到,每次我的应用程序进入后台(当我切换到另一个应用程序时),我都会看到一个从未释放的内存使用跳跃(即使有内存警告) 我可以看出,增加是由一个新的Im
从“React”导入React;
进口{
安全区域视图,
形象,,
}从“反应本机”;
常量应用程序:()=>React$Node=()=>{
返回(
);
};
导出默认应用程序;
我注意到,每次我的应用程序进入后台(当我切换到另一个应用程序时),我都会看到一个从未释放的内存使用跳跃(即使有内存警告)
我可以看出,增加是由一个新的ImageIO_PNG_数据引起的,该数据是在应用程序移动到后台时创建的
虽然这张图片的大小相对较小,但在我的真实应用程序中,它会在用户应用程序频繁切换后导致应用程序崩溃
这是同样的应用程序,同样的图像,用Swift编写,使用同样的方法创建UIRN正在使用的图像
没有额外的图像加载到内存中。RN将这些额外图像加载到内存中而不清除旧图像的做法有什么不同?当应用程序进入后台时会发生什么
更新
在标记了一代人之后,我注意到所有的大图像都来自应用程序进入后台时的iOS快照:
0 libsystem_kernel.dylib mmap
1 ImageIO _ImageIO_Malloc
2 ImageIO AppleJPEGReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*)
3 ImageIO IIO_Reader::CopyImageBlockSetProc(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*)
4 ImageIO IIOImageProviderInfo::CopyImageBlockSetWithOptions(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*)
5 CoreGraphics CGImageProviderCopyImageBlockSetWithOptions
6 QuartzCore CA::Render::copy_image(CGImage*, CGColorSpace*, unsigned int, double, double)
7 QuartzCore CA::Render::prepare_image(CGImage*, CGColorSpace*, unsigned int, double)
8 QuartzCore CA::Layer::prepare_commit(CA::Transaction*)
9 QuartzCore CA::Context::commit_transaction(CA::Transaction*, double)
10 QuartzCore CA::Transaction::commit()
11 UIKitCore __83-[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:]_block_invoke_4
12 UIKitCore -[UIApplication _performWithUICACommitStateSnapshotting:]
13 UIKitCore __83-[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:]_block_invoke_2
14 UIKitCore +[UIView(Animation) performWithoutAnimation:]
15 UIKitCore __83-[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:]_block_invoke
16 UIKitCore -[UIScene _applyOverrideSettings:forActions:]
17 UIKitCore -[UIWindowScene _applySnapshotSettings:forActions:]
18 UIKitCore -[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:]
19 UIKitCore __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_3
20 FrontBoardServices -[FBSSceneSnapshotAction _executeNextRequest]
21 FrontBoardServices -[FBSSceneSnapshotAction _executeNextRequest]
22 FrontBoardServices -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:]
23 UIKitCore __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_2
24 UIKitCore -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:]
25 UIKitCore __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke
26 UIKitCore -[UIScene _enableOverrideSettingsForActions:]
27 UIKitCore -[UIScene _performSystemSnapshotWithActions:]
28 UIKitCore -[UIApplication _performSnapshotsWithAction:forScene:completion:]
29 UIKitCore __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionContext:]_block_invoke_3
30 UIKitCore __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionContext:]_block_invoke.30
31 UIKitCore -[UIApplication prepareSnapshotsWithAction:forScene:completion:]
32 UIKitCore __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionContext:]_block_invoke_2
33 UIKitCore -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:]
34 UIKitCore -[UIScene scene:didUpdateWithDiff:transitionContext:completion:]
35 UIKitCore -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:]
36 FrontBoardServices -[FBSSceneImpl updater:didUpdateSettings:withDiff:transitionContext:completion:]
37 FrontBoardServices __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_block_invoke_2
38 FrontBoardServices -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
39 FrontBoardServices __88-[FBSWorkspaceScenesClient sceneID:updateWithSettingsDiff:transitionContext:completion:]_block_invoke
40 libdispatch.dylib 0x102a9b2a7
41 libdispatch.dylib 0x102a9e9cf
42 FrontBoardServices __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__
43 FrontBoardServices -[FBSSerialQueue _queue_performNextIfPossible]
44 FrontBoardServices -[FBSSerialQueue _performNextFromRunLoopSource]
45 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
46 CoreFoundation __CFRunLoopDoSource0
47 CoreFoundation __CFRunLoopDoSources0
48 CoreFoundation __CFRunLoopRun
49 CoreFoundation CFRunLoopRunSpecific
50 GraphicsServices GSEventRunModal
51 UIKitCore UIApplicationMain
52 tmp main /...
53 libdyld.dylib start
啊,当然,当应用程序进入后台时,操作系统实际上会拍摄应用程序的图片,在后台应用程序中滚动时,该图片会用作预览。在我们的应用程序中,我们执行以下操作:
- (void)deleteAllTemporaryFiles
{
RCTLogInfo(@"[Delegate] Deleting all temp files...");
[self deleteDirectoryFiles:NSTemporaryDirectory()];
[self deleteDirectoryFiles:NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]];
[self deleteDirectoryFiles:NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]];
}
- (void)deleteDirectoryFiles:(NSString *)directory
{
NSArray<NSString *> *temp = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:NULL];
for (NSString *path in temp) {
if (/* check for directories you want to keep here */) continue;
@try {
NSString *filePath = [directory stringByAppendingPathComponent:path];
RCTLogInfo(@"[Delegate] Deleting %@",filePath);
[[NSFileManager defaultManager] removeItemAtPath:filePath error:NULL];
}
@catch (NSException *e) {
RCTLogInfo(@"[Delegate] Deletion error: %@", e);
}
}
}
尝试在组件外部声明
const IMAGE=require('./test.png')
,然后由
使用,可能多次重新渲染会导致内存泄漏。刚刚尝试过,我仍然看到相同的行为。哦,值得一试,可能尝试删除安全视图包装,但没有SafeAreaView恐怕也不走运
// Delete all temp files when app is paused
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self deleteAllTemporaryFiles];
}