Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 内存分配探查器和稳定增加的持久内存-故障迹象?_Ios_Swift_Xcode_Memory Leaks_Instruments - Fatal编程技术网

Ios 内存分配探查器和稳定增加的持久内存-故障迹象?

Ios 内存分配探查器和稳定增加的持久内存-故障迹象?,ios,swift,xcode,memory-leaks,instruments,Ios,Swift,Xcode,Memory Leaks,Instruments,我有一个我正在开发的应用程序,使用它的客户说,在持续使用一整天后,该应用程序变得缓慢、不可用/无响应。杀死它并重新开始会使它运行良好 我的设备上似乎没有这种问题,但我开始在调试器中查看模拟器/手机中的内存使用情况,并观察到如果我采取在屏幕之间切换的基本动作,我的内存将稳步增加。这些都是非常复杂的屏幕,但如果我只转到“添加新项目”屏幕,然后返回到产品列表屏幕,内存会增加30mb。如果我继续做同样的动作,一次又一次,我可以得到1.1gb的内存 然后,我更进一步,挂上我的手机,运行探查器(特别是内存泄

我有一个我正在开发的应用程序,使用它的客户说,在持续使用一整天后,该应用程序变得缓慢、不可用/无响应。杀死它并重新开始会使它运行良好

我的设备上似乎没有这种问题,但我开始在调试器中查看模拟器/手机中的内存使用情况,并观察到如果我采取在屏幕之间切换的基本动作,我的内存将稳步增加。这些都是非常复杂的屏幕,但如果我只转到“添加新项目”屏幕,然后返回到产品列表屏幕,内存会增加30mb。如果我继续做同样的动作,一次又一次,我可以得到1.1gb的内存

然后,我更进一步,挂上我的手机,运行探查器(特别是内存泄漏)。我发现了一个与我使用广告有关的漏洞,所以我只是注释掉了一个测试的所有代码,当漏洞消失后,内存继续稳定地增长

然后我运行了分配工具,以同样的方式来回运行了几分钟后,输出如下:

正如你所看到的,它是1.53GB,如果我继续做同样的动作,我可以让它达到2GB+。奇怪的是,我的手机似乎从来都不介意,而且屏幕有时只是有点滞后,否则就不太糟糕了。当然可以用

在我开始撕地板之前,我想确认这可能是一个问题的迹象。对我可以从哪里开始寻找有什么建议吗?如果持久性内存是个问题,那么典型的陷阱是什么?什么是“匿名虚拟机”

非常感谢您阅读本文,并感谢您的指导

更新/编辑

在这里做了一些指导之后,我注意到,奇怪的是,在“添加产品”页面上,每次我访问它时,它都会导致内存跳跃~10MB。在注释完代码后,我将其缩小到导致跳转的这一部分(甚至是代码行)。删除此代码会使其保持稳定,而不会增加

 //Render collection views
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath as IndexPath) 
        
            let member: MemberDto = groupMembers[indexPath.item]
            let contactInitials = cell.viewWithTag(1) as! UILabel
            let contactAvatar = cell.viewWithTag(2) as! UIImageView
            contactAvatar.image = UIImage(named: "anonymous")
            contactInitials.text = member.displayName
            contactAvatar.layer.cornerRadius = contactAvatar.frame.size.width / 2
            contactAvatar.clipsToBounds = true
            contactAvatar.contentMode = UIViewContentMode.scaleAspectFill
            contactAvatar.layer.borderWidth = 5.0

            
             
            if (member.profileImage.trimmingCharacters(in: CharacterSet.whitespaces) != "") {
                UserService.getProfilePicture(userId: member.userId) {
                    response in
                    
                    contactAvatar.image = response.value
                }
            }
          
因此,这里是有问题的代码行:

 contactAvatar.image = response.value
将其添加到tableviewcontroller中,并来回转到该tableviewcontroller会导致内存不断增加,一直增加到2gb。删除这一行代码(在我设置图像的地方)可以使其稳定在约40-70mb,或者它上升得非常慢(几十次重复只能使其达到80mb)

我意识到我没有缓存此图像

我决定尝试用我的框架缓存它,这立即解决了这个问题。我想这行代码是把图像放到内存里还是什么的?网络调用似乎不是真正的问题,因为我把它留在了中(甚至还对我的API进行了额外的调用),而这似乎对内存的增加没有多大作用

 //Render collection views
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath as IndexPath) 
        
            let member: MemberDto = groupMembers[indexPath.item]
            let contactInitials = cell.viewWithTag(1) as! UILabel
            let contactAvatar = cell.viewWithTag(2) as! UIImageView
            contactAvatar.image = UIImage(named: "anonymous")
            contactInitials.text = member.displayName
            contactAvatar.layer.cornerRadius = contactAvatar.frame.size.width / 2
            contactAvatar.clipsToBounds = true
            contactAvatar.contentMode = UIViewContentMode.scaleAspectFill
            contactAvatar.layer.borderWidth = 5.0

            
             
            if (member.profileImage.trimmingCharacters(in: CharacterSet.whitespaces) != "") {
                UserService.getProfilePicture(userId: member.userId) {
                    response in
                    
                    contactAvatar.image = response.value
                }
            }
          
只是一些信息:

  • 在主屏幕上,点击导航菜单栏中的+符号可进入此屏幕
  • 我在故事板上使用与navigationbutton关联的常规segue将用户带到这里
  • 在这个vc上放置Denit似乎从来没有成功过,即使有打印/代码和断点
  • 从uitableviewcontroller中进行API调用似乎不会导致图像加载,除非我将其与图像设置结合起来。如果我打一个网络电话,但不设置映像,它不会增加
我犯了什么错误?我觉得缓存图像就像一张绷带——我记得读到过这样一篇文章,你不应该在UITableViewController中调用图像,但还有什么办法,可以提前从集合中提取所有用户图像,并在加载tableview之前缓存它们

编辑2

正如@matt所说,这只是一张绷带。真正的问题仍然存在,因为我知道没有调用deinit()。在取出主要的代码块后,我发现

lblMessage.addTapGestureRecognizer {
            self.txtMessage.becomeFirstResponder()
        }
        
映射到扩展类的:

public func addTapGestureRecognizer(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.tapGestureRecognizerAction = action
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
        self.addGestureRecognizer(tapGestureRecognizer)
    }
    public func addLongPressGestureRecognizer(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.longPressGestureRecognizerAction = action
        let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture))
        self.addGestureRecognizer(longPressGestureRecognizer)
    }
     
    
    // Every time the user taps on the View, this function gets called,
    // which triggers the closure we stored
    @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
        if let action = self.tapGestureRecognizerAction {
            action?()
        } else {
            print("no action")
        }
    }
所以问题一定在这里的某个地方。我将把它带到一个新的线程:


谢谢!希望这对某人有所帮助。

是的,这是个问题,是的,你需要解决它。这类事情的两个常见原因是:

  • 您已经有了一个保留周期,至少您的一些视图控制器永远无法消失

  • 您错误地设计了情节串连板(或手动序列)序列,因此(例如)您从视图控制器A到视图控制器B呈现<代码>,然后为了“返回”,您从控制器B到视图控制器A呈现<代码>。因此,您实际上没有“返回”;相反,您将在第一个视图控制器的顶部堆积第二个视图控制器a,以此类推,直到永远


无论哪种方式,只要在所有视图控制器中实现
deinit
print(self)
,就可以快速测试这类事情是否正在进行。然后玩应用程序。如果您每次“返回”时都没有在日志中看到打印输出,那么您就有了严重的内存问题,因为视图控制器没有在应该释放的时候释放,您需要修复它。

是的,这是一个问题,是的,您需要修复它。这类事情的两个常见原因是:

  • 您已经有了一个保留周期,至少您的一些视图控制器永远无法消失

  • 您错误地设计了情节串连板(或手动序列)序列,因此(例如)您从视图控制器A到视图控制器B呈现<代码>,然后为了“返回”,您从控制器B到视图控制器A呈现<代码>。因此,您实际上没有“返回”;相反,您将在第一个视图控制器的顶部堆积第二个视图控制器a,以此类推,直到永远

无论采用哪种方式,只要将
deinit
实现为
print,就可以快速测试这类事情是否正在进行