Skip to content

Commit 1cf9783

Browse files
fix: clean up chunk memory (#101)
* avoid keeping a reference to the file chunk in ChunkWorker When the Worker actor loops over a file, it does not always deallocate file chunks until the loop completes. Because each ChunkWorker is intended to be only used once, it is not necessary to keep a reference to its file chunk beyond the upload task call. --------- Co-authored-by: AJ Lauer Barinov <abarinov@mux.com>
1 parent d582130 commit 1cf9783

File tree

6 files changed

+290
-78
lines changed

6 files changed

+290
-78
lines changed

Example/SwiftUploadSDKExample/SwiftUploadSDKExample.xcodeproj/project.pbxproj

Lines changed: 143 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
19822A772A4CA69700CFA822 /* UploadCTA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19822A662A4CA69700CFA822 /* UploadCTA.swift */; };
2727
19822A792A4CA69700CFA822 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19822A682A4CA69700CFA822 /* ImagePicker.swift */; };
2828
19DCD95B2A4CA567001FBBF6 /* MuxUploadSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 19DCD95A2A4CA567001FBBF6 /* MuxUploadSDK */; };
29+
F38876D22B86DCFB00B82A86 /* MuxUploadSDK in Frameworks */ = {isa = PBXBuildFile; productRef = F38876D12B86DCFB00B82A86 /* MuxUploadSDK */; };
2930
/* End PBXBuildFile section */
3031

3132
/* Begin PBXContainerItemProxy section */
@@ -36,6 +37,13 @@
3637
remoteGlobalIDString = 358E3C7629A92167005261CB;
3738
remoteInfo = "Test App";
3839
};
40+
F38876CB2B86DBEB00B82A86 /* PBXContainerItemProxy */ = {
41+
isa = PBXContainerItemProxy;
42+
containerPortal = 358E3C6F29A92167005261CB /* Project object */;
43+
proxyType = 1;
44+
remoteGlobalIDString = 358E3C7629A92167005261CB;
45+
remoteInfo = SwiftUploadSDKExample;
46+
};
3947
/* End PBXContainerItemProxy section */
4048

4149
/* Begin PBXFileReference section */
@@ -60,6 +68,7 @@
6068
19DCD9592A4CA546001FBBF6 /* swift-upload-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "swift-upload-sdk"; path = ../..; sourceTree = "<group>"; };
6169
358E3C7729A92167005261CB /* SwiftUploadSDKExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUploadSDKExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
6270
358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftUploadSDKExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
71+
F38876C72B86DBEB00B82A86 /* .xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = .xctest; sourceTree = BUILT_PRODUCTS_DIR; };
6372
/* End PBXFileReference section */
6473

6574
/* Begin PBXFrameworksBuildPhase section */
@@ -78,6 +87,14 @@
7887
);
7988
runOnlyForDeploymentPostprocessing = 0;
8089
};
90+
F38876C42B86DBEB00B82A86 /* Frameworks */ = {
91+
isa = PBXFrameworksBuildPhase;
92+
buildActionMask = 2147483647;
93+
files = (
94+
F38876D22B86DCFB00B82A86 /* MuxUploadSDK in Frameworks */,
95+
);
96+
runOnlyForDeploymentPostprocessing = 0;
97+
};
8198
/* End PBXFrameworksBuildPhase section */
8299

83100
/* Begin PBXGroup section */
@@ -175,6 +192,7 @@
175192
358E3CC329A9221F005261CB /* Packages */,
176193
19822A502A4CA69700CFA822 /* SwiftUploadSDKExample */,
177194
19822A7A2A4CA6A300CFA822 /* SwiftUploadSDKExampleTests */,
195+
F38876C82B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */,
178196
358E3C7829A92167005261CB /* Products */,
179197
358E3CC529A9223B005261CB /* Frameworks */,
180198
);
@@ -185,6 +203,7 @@
185203
children = (
186204
358E3C7729A92167005261CB /* SwiftUploadSDKExample.app */,
187205
358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */,
206+
F38876C72B86DBEB00B82A86 /* .xctest */,
188207
);
189208
name = Products;
190209
sourceTree = "<group>";
@@ -204,6 +223,13 @@
204223
name = Frameworks;
205224
sourceTree = "<group>";
206225
};
226+
F38876C82B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */ = {
227+
isa = PBXGroup;
228+
children = (
229+
);
230+
path = SwiftUploadSDKExampleUnitTests;
231+
sourceTree = "<group>";
232+
};
207233
/* End PBXGroup section */
208234

209235
/* Begin PBXNativeTarget section */
@@ -245,14 +271,35 @@
245271
productReference = 358E3C9129A92168005261CB /* SwiftUploadSDKExampleTests.xctest */;
246272
productType = "com.apple.product-type.bundle.ui-testing";
247273
};
274+
F38876C62B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */ = {
275+
isa = PBXNativeTarget;
276+
buildConfigurationList = F38876CD2B86DBEB00B82A86 /* Build configuration list for PBXNativeTarget "SwiftUploadSDKExampleUnitTests" */;
277+
buildPhases = (
278+
F38876C32B86DBEB00B82A86 /* Sources */,
279+
F38876C42B86DBEB00B82A86 /* Frameworks */,
280+
F38876C52B86DBEB00B82A86 /* Resources */,
281+
);
282+
buildRules = (
283+
);
284+
dependencies = (
285+
F38876CC2B86DBEB00B82A86 /* PBXTargetDependency */,
286+
);
287+
name = SwiftUploadSDKExampleUnitTests;
288+
packageProductDependencies = (
289+
F38876D12B86DCFB00B82A86 /* MuxUploadSDK */,
290+
);
291+
productName = SwiftUploadSDKExampleUnitTests;
292+
productReference = F38876C72B86DBEB00B82A86 /* .xctest */;
293+
productType = "com.apple.product-type.bundle.unit-test";
294+
};
248295
/* End PBXNativeTarget section */
249296

250297
/* Begin PBXProject section */
251298
358E3C6F29A92167005261CB /* Project object */ = {
252299
isa = PBXProject;
253300
attributes = {
254301
BuildIndependentTargetsInParallel = 1;
255-
LastSwiftUpdateCheck = 1420;
302+
LastSwiftUpdateCheck = 1500;
256303
LastUpgradeCheck = 1420;
257304
TargetAttributes = {
258305
358E3C7629A92167005261CB = {
@@ -262,6 +309,10 @@
262309
CreatedOnToolsVersion = 14.2;
263310
TestTargetID = 358E3C7629A92167005261CB;
264311
};
312+
F38876C62B86DBEB00B82A86 = {
313+
CreatedOnToolsVersion = 15.0.1;
314+
TestTargetID = 358E3C7629A92167005261CB;
315+
};
265316
};
266317
};
267318
buildConfigurationList = 358E3C7229A92167005261CB /* Build configuration list for PBXProject "SwiftUploadSDKExample" */;
@@ -273,12 +324,16 @@
273324
Base,
274325
);
275326
mainGroup = 358E3C6E29A92167005261CB;
327+
packageReferences = (
328+
F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */,
329+
);
276330
productRefGroup = 358E3C7829A92167005261CB /* Products */;
277331
projectDirPath = "";
278332
projectRoot = "";
279333
targets = (
280334
358E3C7629A92167005261CB /* SwiftUploadSDKExample */,
281335
358E3C9029A92168005261CB /* SwiftUploadSDKExampleTests */,
336+
F38876C62B86DBEB00B82A86 /* SwiftUploadSDKExampleUnitTests */,
282337
);
283338
};
284339
/* End PBXProject section */
@@ -301,6 +356,13 @@
301356
);
302357
runOnlyForDeploymentPostprocessing = 0;
303358
};
359+
F38876C52B86DBEB00B82A86 /* Resources */ = {
360+
isa = PBXResourcesBuildPhase;
361+
buildActionMask = 2147483647;
362+
files = (
363+
);
364+
runOnlyForDeploymentPostprocessing = 0;
365+
};
304366
/* End PBXResourcesBuildPhase section */
305367

306368
/* Begin PBXSourcesBuildPhase section */
@@ -333,6 +395,13 @@
333395
);
334396
runOnlyForDeploymentPostprocessing = 0;
335397
};
398+
F38876C32B86DBEB00B82A86 /* Sources */ = {
399+
isa = PBXSourcesBuildPhase;
400+
buildActionMask = 2147483647;
401+
files = (
402+
);
403+
runOnlyForDeploymentPostprocessing = 0;
404+
};
336405
/* End PBXSourcesBuildPhase section */
337406

338407
/* Begin PBXTargetDependency section */
@@ -341,6 +410,11 @@
341410
target = 358E3C7629A92167005261CB /* SwiftUploadSDKExample */;
342411
targetProxy = 358E3C9229A92168005261CB /* PBXContainerItemProxy */;
343412
};
413+
F38876CC2B86DBEB00B82A86 /* PBXTargetDependency */ = {
414+
isa = PBXTargetDependency;
415+
target = 358E3C7629A92167005261CB /* SwiftUploadSDKExample */;
416+
targetProxy = F38876CB2B86DBEB00B82A86 /* PBXContainerItemProxy */;
417+
};
344418
/* End PBXTargetDependency section */
345419

346420
/* Begin XCBuildConfiguration section */
@@ -481,7 +555,6 @@
481555
"@executable_path/Frameworks",
482556
);
483557
MARKETING_VERSION = 1.0;
484-
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-App";
485558
PRODUCT_NAME = "$(TARGET_NAME)";
486559
SWIFT_EMIT_LOC_STRINGS = YES;
487560
SWIFT_VERSION = 5.0;
@@ -513,7 +586,6 @@
513586
"@executable_path/Frameworks",
514587
);
515588
MARKETING_VERSION = 1.0;
516-
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-App";
517589
PRODUCT_NAME = "$(TARGET_NAME)";
518590
PROVISIONING_PROFILE_SPECIFIER = "";
519591
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -531,7 +603,6 @@
531603
DEVELOPMENT_TEAM = "";
532604
GENERATE_INFOPLIST_FILE = YES;
533605
MARKETING_VERSION = 1.0;
534-
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-AppUITests";
535606
PRODUCT_NAME = "$(TARGET_NAME)";
536607
SWIFT_EMIT_LOC_STRINGS = NO;
537608
SWIFT_VERSION = 5.0;
@@ -549,7 +620,6 @@
549620
DEVELOPMENT_TEAM = "";
550621
GENERATE_INFOPLIST_FILE = YES;
551622
MARKETING_VERSION = 1.0;
552-
PRODUCT_BUNDLE_IDENTIFIER = "com.mux.video.upload.Test-AppUITests";
553623
PRODUCT_NAME = "$(TARGET_NAME)";
554624
SWIFT_EMIT_LOC_STRINGS = NO;
555625
SWIFT_VERSION = 5.0;
@@ -558,6 +628,49 @@
558628
};
559629
name = Release;
560630
};
631+
F38876CE2B86DBEB00B82A86 /* Debug */ = {
632+
isa = XCBuildConfiguration;
633+
buildSettings = {
634+
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
635+
BUNDLE_LOADER = "$(TEST_HOST)";
636+
CODE_SIGN_STYLE = Automatic;
637+
CURRENT_PROJECT_VERSION = 1;
638+
DEVELOPMENT_TEAM = "";
639+
ENABLE_USER_SCRIPT_SANDBOXING = YES;
640+
GCC_C_LANGUAGE_STANDARD = gnu17;
641+
GENERATE_INFOPLIST_FILE = YES;
642+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
643+
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
644+
MARKETING_VERSION = 1.0;
645+
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
646+
SWIFT_EMIT_LOC_STRINGS = NO;
647+
SWIFT_VERSION = 5.0;
648+
TARGETED_DEVICE_FAMILY = "1,2";
649+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUploadSDKExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftUploadSDKExample";
650+
};
651+
name = Debug;
652+
};
653+
F38876CF2B86DBEB00B82A86 /* Release */ = {
654+
isa = XCBuildConfiguration;
655+
buildSettings = {
656+
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
657+
BUNDLE_LOADER = "$(TEST_HOST)";
658+
CODE_SIGN_STYLE = Automatic;
659+
CURRENT_PROJECT_VERSION = 1;
660+
DEVELOPMENT_TEAM = "";
661+
ENABLE_USER_SCRIPT_SANDBOXING = YES;
662+
GCC_C_LANGUAGE_STANDARD = gnu17;
663+
GENERATE_INFOPLIST_FILE = YES;
664+
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
665+
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
666+
MARKETING_VERSION = 1.0;
667+
SWIFT_EMIT_LOC_STRINGS = NO;
668+
SWIFT_VERSION = 5.0;
669+
TARGETED_DEVICE_FAMILY = "1,2";
670+
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUploadSDKExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/SwiftUploadSDKExample";
671+
};
672+
name = Release;
673+
};
561674
/* End XCBuildConfiguration section */
562675

563676
/* Begin XCConfigurationList section */
@@ -588,13 +701,38 @@
588701
defaultConfigurationIsVisible = 0;
589702
defaultConfigurationName = Release;
590703
};
704+
F38876CD2B86DBEB00B82A86 /* Build configuration list for PBXNativeTarget "SwiftUploadSDKExampleUnitTests" */ = {
705+
isa = XCConfigurationList;
706+
buildConfigurations = (
707+
F38876CE2B86DBEB00B82A86 /* Debug */,
708+
F38876CF2B86DBEB00B82A86 /* Release */,
709+
);
710+
defaultConfigurationIsVisible = 0;
711+
defaultConfigurationName = Release;
712+
};
591713
/* End XCConfigurationList section */
592714

715+
/* Begin XCRemoteSwiftPackageReference section */
716+
F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */ = {
717+
isa = XCRemoteSwiftPackageReference;
718+
repositoryURL = "https://github.com/muxinc/swift-upload-sdk";
719+
requirement = {
720+
branch = main;
721+
kind = branch;
722+
};
723+
};
724+
/* End XCRemoteSwiftPackageReference section */
725+
593726
/* Begin XCSwiftPackageProductDependency section */
594727
19DCD95A2A4CA567001FBBF6 /* MuxUploadSDK */ = {
595728
isa = XCSwiftPackageProductDependency;
596729
productName = MuxUploadSDK;
597730
};
731+
F38876D12B86DCFB00B82A86 /* MuxUploadSDK */ = {
732+
isa = XCSwiftPackageProductDependency;
733+
package = F38876D02B86DCFB00B82A86 /* XCRemoteSwiftPackageReference "swift-upload-sdk" */;
734+
productName = MuxUploadSDK;
735+
};
598736
/* End XCSwiftPackageProductDependency section */
599737
};
600738
rootObject = 358E3C6F29A92167005261CB /* Project object */;

Example/SwiftUploadSDKExample/SwiftUploadSDKExample.xcodeproj/xcshareddata/xcschemes/SwiftUploadSDKExample.xcscheme

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@
4040
ReferencedContainer = "container:SwiftUploadSDKExample.xcodeproj">
4141
</BuildableReference>
4242
</TestableReference>
43+
<TestableReference
44+
skipped = "NO"
45+
parallelizable = "YES">
46+
<BuildableReference
47+
BuildableIdentifier = "primary"
48+
BlueprintIdentifier = "F38876C62B86DBEB00B82A86"
49+
BuildableName = "SwiftUploadSDKExampleUnitTests.xctest"
50+
BlueprintName = "SwiftUploadSDKExampleUnitTests"
51+
ReferencedContainer = "container:SwiftUploadSDKExample.xcodeproj">
52+
</BuildableReference>
53+
</TestableReference>
4354
</Testables>
4455
</TestAction>
4556
<LaunchAction

Sources/MuxUploadSDK/InternalUtilities/ChunkedFile.swift

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,47 @@ class ChunkedFile {
4141
func readNextChunk() -> Result<FileChunk, Error> {
4242
SDKLogger.logger?.info("--readNextChunk(): called")
4343
do {
44-
guard fileHandle != nil else {
44+
guard let fileHandle else {
4545
return Result.failure(ChunkedFileError.invalidState("readNextChunk() called but the file was not open"))
4646
}
47-
return try Result.success(doReadNextChunk())
47+
48+
guard let fileURL = fileURL else {
49+
return Result.failure(ChunkedFileError.invalidState("Missing file url."))
50+
}
51+
var data : Data?
52+
try autoreleasepool {
53+
data = try fileHandle.read(upToCount: chunkSize)
54+
}
55+
56+
let fileSize = try fileManager.fileSizeOfItem(
57+
atPath: fileURL.path
58+
)
59+
60+
guard let data = data else {
61+
// Called while already at the end of the file. We read zero bytes, "ending" at the end of the file
62+
return .success(
63+
FileChunk(
64+
startByte: fileSize,
65+
endByte: fileSize,
66+
totalFileSize: fileSize,
67+
chunkData: Data(capacity: 0)
68+
)
69+
)
70+
}
71+
72+
let chunkLength = data.count
73+
let updatedFilePosition = filePos + UInt64(chunkLength)
74+
75+
let chunk = FileChunk(
76+
startByte: self.filePos,
77+
endByte: updatedFilePosition,
78+
totalFileSize: fileSize,
79+
chunkData: data
80+
)
81+
82+
state?.filePosition = updatedFilePosition
83+
84+
return .success(chunk)
4885
} catch {
4986
return Result.failure(ChunkedFileError.fileHandle(error))
5087
}
@@ -91,8 +128,11 @@ class ChunkedFile {
91128
guard let fileHandle = fileHandle, let fileURL = fileURL else {
92129
throw ChunkedFileError.invalidState("doReadNextChunk called without file handle. Did you call open()?")
93130
}
94-
let data = try fileHandle.read(upToCount: chunkSize)
95-
131+
var data : Data?
132+
try autoreleasepool {
133+
data = try fileHandle.read(upToCount: chunkSize)
134+
}
135+
96136
let fileSize = try fileManager.fileSizeOfItem(
97137
atPath: fileURL.path
98138
)
@@ -131,7 +171,7 @@ struct FileChunk {
131171
/// Exclusive
132172
let endByte: UInt64
133173
let totalFileSize: UInt64
134-
let chunkData: Data
174+
var chunkData: Data
135175

136176
func size() -> Int {
137177
return Int(endByte - startByte) // This is safe for any reasonable chunk size

0 commit comments

Comments
 (0)