The following code allocates a bunch of big structs in dispatch queues, and it crashes consistently for me when using DispatchQueue.concurrentPerform or NSArray.enumerateObjects, but not when just executing on a background queue.
Is there some queue-specific stack-size limit that can be adjusted?
import Dispatch
import Foundation
import XCTest
class QueueMemoryAllocCrashTest : XCTestCase {
/// Eight is enough
struct OctoThing {
let t1, t2, t3, t4, t5, t6, t7, t8: T
}
/// A 32K block of memory
struct MemoryChunk {
let chunk: OctoThing<octothing<octothing<octothing>>>? = nil // 32,768 bytes
}
/// This function does nothing but waste stack space (491,520 bytes to be specific)
func wasteMemory() {
// any fewer than 15 of these and the test will pass
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
let _ = MemoryChunk()
}
func testWasteOnQueue() {
// this passes without any problems
DispatchQueue.global(qos: .userInteractive).sync(execute: {
wasteMemory()
wasteMemory()
wasteMemory()
})
}
func testWasteWithConcurrentPerform() {
// this crashes with 2 iterations or more with a EXC_BAD_ACCESS
DispatchQueue.concurrentPerform(iterations: 2, execute: { _ in
wasteMemory()
})
}
func testWasteWithEnumerateObjects() {
// this crashes with 17 iterations or more with a EXC_BAD_ACCESS
(Array(1...17) as NSArray).enumerateObjects(options: [.concurrent]) { _, _, _ in
wasteMemory()
}
}
}