[英]Unable to locate memory leak using Xcode Instruments
較早時,我發現游戲中的內存使用量僅在移動磁貼時才增加,但再也沒有回落。 由此,我可以判斷出內存泄漏。
然后,我開始使用Xcode Instruments,這是我的新手。 因此,我遵循了本文中的許多內容,尤其是“ Recording Options
,然后設置了顯示“ Call Tree
的模式。
我有兩個函數,它們僅沿着該行/列移動所有node.copy()
貼,然后在末尾克隆node.copy()
貼(使用node.copy()
),以便所有內容都可以“循環播放”,因此是項目名稱。
我覺得瓦片克隆可能會導致某些保留周期,但是它存儲在函數范圍內的變量中。 在克隆上運行SKAction
之后,我使用copiedNode.removeFromParent()
從場景中刪除了圖塊。
那么什么原因可能導致此內存泄漏? 我可以找錯地方嗎?
我已將此代碼縮短為我認為必要的代碼。
在班級頂部的聲明:
/// Delegate to the game scene to reference properties.
weak var delegate: GameScene!
/// All the cloned tiles currently on the board.
private var cloneTiles = [SKSpriteNode]()
在活動磁貼中克隆磁貼的功能是:
/// A duplicate of the current tile.
let copiedNode = currentTile.node.copy() as! SKSpriteNode // Create copy
cloneTiles.append(copiedNode) // Add as a clone
delegate.addChild(copiedNode) // Add to the scene
let copiedNodeAction = SKAction.moveBy(x: movementDifference, y: 0, duration: animationDuration) // Create the movement action
// Run the action, and then remove itself
copiedNode.run(copiedNodeAction) {
self.cloneTiles.remove(at: self.cloneTiles.firstIndex(of: copiedNode)!)
copiedNode.removeFromParent()
}
立即移動圖塊的功能:
/// Move all tiles to the correct location immediately.
private func moveTilesToLocationImmediately() {
// Remove all clone tiles
cloneTiles.forEach { $0.removeFromParent() }
cloneTiles.removeAll()
/* Moves tiles here */
}
有什么我需要聲明為weak var
東西嗎? 我知道保留周期是如何發生的,但是由於我從cloneTiles
數組中刪除了克隆的tile引用,所以不知道為什么它存在於此代碼中。
Mark Szymczyk
幫助) 這是我雙擊調用堆棧中的move tile函數后發生的情況(請參見下面的答案):
這可以確認內存泄漏是由節點克隆以某種方式引起的,但是我仍然不知道為什么在從cloneTiles
數組和場景中刪除該節點后仍保留該節點。 節點是否可能由於某種原因而無法從場景中移除?
請留下任何有關此的提示或問題,以便可以解決此問題!
我現在一直在嘗試與Xcode Instruments接觸,但是我仍然真的很難找到這種內存泄漏。 這是泄漏面板,可能會有所幫助:
即使嘗試過[weak self]
,我仍然沒有運氣:
甚至在閉包內的[weak self]
,泄漏歷史看起來仍然相同。
目前, @matt
正在幫助我解決此問題。 通過添加[unowned self]
類的東西,我更改了幾行代碼:
// Determine if the tile will roll over
if direction == .up && movementDifference < 0 || direction == .down && movementDifference > 0 {
// Calculate where the clone tile should move to
movementDifference -= rollOverDistance
/// A duplicate of the current tile.
let copiedNode = currentTile.node.copy() as! SKSpriteNode // Create copy
cloneTiles.append(copiedNode) // Add as a clone
delegate.addChild(copiedNode) // Add to the scene
let copiedNodeAction = SKAction.moveBy(x: 0, y: movementDifference, duration: animationDuration) // Create the movement action
// Run the action, and then remove itself
copiedNode.run(copiedNodeAction) { [unowned self, copiedNode] in
self.cloneTiles.remove(at: self.cloneTiles.firstIndex(of: copiedNode)!).removeFromParent()
}
// Move the original roll over tile back to the other side of the screen
currentTile.node.position.y += rollOverDistance
}
/// The normal action to perform, moving the tile by a distance.
let normalNodeAction = SKAction.moveBy(x: 0, y: movementDifference, duration: animationDuration) // Create the action
currentTile.node.run(normalNodeAction) { [unowned self] in // Apply the action
if forRow == 1 { self.animationsCount -= 1 } // Lower animation count for completion
}
不幸的是,我無法將copiedNode
weak
屬性,因為它總是立即變為nil
,並且unowned
導致釋放引用后讀取引用時發生崩潰。 如果有幫助,這也是“ Cycles & Roots
圖:
感謝您的任何幫助!
我可以在樂器方面提供一些幫助。 如果您在Instruments調用樹中雙擊moveHorizontally
條目,則Instruments將向您顯示分配泄漏內存的代碼行。 窗口底部是“呼叫樹”按鈕。 如果單擊該按鈕,則可以反轉調用樹並隱藏系統庫。 這樣做將使在調用樹中查找代碼更加容易。
您可以在以下文章中了解有關Instruments的更多信息:
我對您管理復制節點的方式非常懷疑; 您可能會過早釋放它,並且只有保留周期才阻止您發現此錯誤。 但是,讓我們集中精力打破保留周期。
您想要做的是使進入該動作方法的所有內容都變weak
,以使該動作方法沒有強大的捕獲能力。 然后,在操作方法中,您要立即保留那些弱引用,以免它們從您的下方消失。 這就是所謂的“弱勁舞”。 像這樣:
copiedNode.run(copiedNodeAction) { [weak self, weak copiedNode] in
if let `self` = self, let copiedNode = copiedNode {
// do stuff here
// be sure to log so you know we arrived here at all, as we might not
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.