引用, 强弱引用, 事件机制与垃圾回收的关系及应用法则

2024-04-03 11:38

本文主要是介绍引用, 强弱引用, 事件机制与垃圾回收的关系及应用法则,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

经常见朋友们提起 “资源占用” 与 “垃圾回收”机制, 此类情况有常常伴随 事件机制与显示列表相关问题,还有诸如此类的强弱引用的问题,关系错综复杂,令人困惑不小。在经过一番整理和测试研究后决定拿出来和大家一起分享一下心得,共同促进天地会的壮大。

先来说说一些基本概念( 不完全遵从于课本,理解不准确请见笑 ):

1.引用类型与值类型的关系:
   值类型属于简单数据类型( Nmber/String/uint...), 具有可复制性,就像一本书可以被发行数万册一样,每本书都出自于同一版,只是相同内容的复制而已;
  引用类型属于复杂数据类型( XML/Sprite/Object...), 具有唯一性,  如同一个人办了很多信用卡,但所有帐号都对应同一个人; 你可以被称为张三/经理/老公, 但这个世界只有一个你,You are the No.1
   引用可以被理解为 对象的一个 “标示”,是为了区分和操作对象起来方便一些, 如同每个人的名字一样。

2. 强引用与弱引用:
  强引用也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示列表中,则此对象会被从内存中释放。
  弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个若引用,只要没有强引用指向他,那麽其还是会被清除。没办法,还是 “强哥” 有面子。
  临时变量 < 弱引用 < 强引用 = 字段引用

3. AS3.0 是一个面向对象的事件驱动的高级语言,可见事件在其中的位置。 事件分为 "事件触发者", "事件对象",  "事件接收者 ". 事件可以大大降低各个对象之间的耦合性, 灵活的传递参数,在Caigrom Framework 事件的地位很重要。如果事件触发者没了,那么事件接收者也就不会接收到事件; 如果事件接收者没了, 那就等于事件不会被接收; 事件对象在事件执行完毕后会被释放。
鉴于篇幅这里就不过多的讲述了。

4. 垃圾回收
  垃圾回收是虚拟机中的内存管理机制,是为了清除掉内存中的闲置资源和实现内存碎片的整理。垃圾回收究竟何时运行我没有具体研究,有兴趣的朋友可以去自 行了解下, 不过经过测试发现 :当系统出现异常时( 例如 : IO_Error ) 垃圾回收会自动运行。其实现原则是这样的 : 对象不存在于显示列表,并且不存在指向对象的引用,那麽此对象会被从内存中释放,这句话听起来很简洁,但如果与其他情况混到一起 往往让人无所适从,不知道何种情况下对象才会被释放,下面将展开对此问题的逐步讨论:

     先看一段代码:
       private function loadTest() : void
       {
              var loader : URLLoader = new URLLoader();
               loader.addEventListener( Event.COMPLETE, loadedHandler );
               loader.loader( new URLRequest( "url" ) );

        }

        private function loadedHandler( evt : Event ) : void
        {
               ( evt.target  as Loader ).removeListener(  Event.COMPLETE, loadedHandler );
               // Do others.
         }
         
         函数 loadTest() 中声明了一个临时变量 "loader", 此事件触发者 "loader" 持有对 loadedHandler () 函数的引用,用来处理事件, 我们先来简单分析一下:
      A : loader 何时被回收?
         loader 是个临时变量,此引用是临时的,生存期很短暂,只在 loadTest() 函数内有效, 所以可以理解为 : 不存在指向 "loader" 的引用。但 loader 并不会马上被内存释放, 因为其还没有执行
      完, 当 加载完成或IO错误时 loader 才会被释放, 其持有的 loadedHandler() 函数的引用随之消亡。类似此类的还有 建立连接, 打开本地文件之类的情况, 只有执行完毕/关闭连接后 对象才
      可以被释放。

      B : 假设 此段代码 位于 TargetClass 中,  如果 TargetClass 也是被临时创建的, 那麽他何时被释放?
      只有当载入事件执行完毕时 TargetClass 才可以被释放,因为这时 loader 才可以被释放,loader 间接持有 TargetClass 的引用,loader被释放-> TargetClass 的引用 消亡 -> TargetClass 被释放。

      C : 如果  loader.addEventListener( Event.COMPLETE, loadedHandler, false, 0, true ) :  loader 持有 TargetClass 的弱引用, 这时谁先消亡,谁后消亡?
      弱引用不影响到对象的消亡, 所以 : TargetClass 会瞬间被释放, loader 执行完才会被释放, 也不会执行 loadedHandler();

         D:  当 loader 是 TargetClass 中的一个字段( TargetClass 的一个属性/变量) , 他们又将如何消亡?

         private var loader : URLLoader;
         private function loadTest() : void
         {
               loader = new URLLoader();
               loader.addEventListener( Event.COMPLETE, loadedHandler );
               loader.loader( new URLRequest( "url" ) );
        }

        TargetClass 间接 持有自身的引用, loader 执行期内, TargetClass 不能被回收, loader 执行完毕后 两者一起被回收。 象这种 : 对象间接(  不管间接多少层 ) 或直接持有自身的引用
     不会影响对象的释放,即使不清除事件监听和"实现间接的对象" 他们也会被释放。

     E : 如果向上述情况中,loader 采用弱引用监听, 那么谁先被释放?
     此时,TargetClass 会瞬间被释放, loader 执行完毕后被释放。那么有人问了: loader 是TargetClass中的一个字段, 怎么可以 TargetClass 先被释放, 而 loader 后被释放呢?
     其实 loader 只是 TargetClass 持有的一个引用字段, 他并不是 URLLoader 本身( 不能说TargetClass 包含URLLoader), TargetClass 释放后 loader 引用也就消除了, 但已被创建的
     URLLoader 等到执行完毕后才会被释放。

     重复上述原则: 对象不存在于显示列表, 且不存在指向对象的引用,那麽此对象会被从内存中释放. 那么对象如何才算被引用(直接/间接)?
     F : 如果我在 TargetClass 外部 建立一个对于 loader 的引用(  把loader 的作用域公开), 那麽是不是就等于我间接的持有了TargetClass 的引用, TargetClass 不会被释放呢?
       答案是 : TargetClass 会被释放, loader 即使执行完都不会被释放。 TargetClass 被释放时同时释放了 指向 URLLoader 的一个引用 "loader", TargetClass 外部还有一个引用指向 这个  URLLoader, 所以"这个URLLoader" 不会被释放。引用对象的的字段不能算是间接引用对象, 引用对象中的方法才算是间接引用对象( 可以看出对象更强调其行为 ),这样此对象被持有引用, 不会被释放。

    听起来似乎还是很乱, 没关系, 接触多了自然就会搞清楚他们之间的关系, 下面提出几点法则供大家参考:

    1. 尽可能让对象自身的存亡不要影响到别人, 所以尽可能的使用弱引用, 除非你有特殊情况。
    2.对于永远存在的对象, 永远让其持有其他对象的弱引用。 例如 stage.addEventListener( MouseEvent.MOUSE_MOVE, object.moveHandler, false, 0, true );
      3. 养成良好的习惯, 事件执行完一定要移除监听(  清除引用 ), 连接执行完一定要关闭连接.............., 自己产生的垃圾,自己清理,不要乱扔果皮和烟头......   
      4.如果一个对象不会被多次方访问,那么没必要给其分配一个字段引用, 如一些皮肤 , 只要将其添加到显示列表就OK了, 没必要给他个 引用,多一事不如少一事。
      5. 局部性的业务逻辑,尽可能不要用诸如 C airGorm 中的 全局事件, 冒泡法就可以解决, 全局性的逻辑再用全局事件, 局部耦合性可以高一点, 但全局一定要耦合小。

这篇关于引用, 强弱引用, 事件机制与垃圾回收的关系及应用法则的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/872812

相关文章

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

MYSQL关联关系查询方式

《MYSQL关联关系查询方式》文章详细介绍了MySQL中如何使用内连接和左外连接进行表的关联查询,并展示了如何选择列和使用别名,文章还提供了一些关于查询优化的建议,并鼓励读者参考和支持脚本之家... 目录mysql关联关系查询关联关系查询这个查询做了以下几件事MySQL自关联查询总结MYSQL关联关系查询

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例

5分钟获取deepseek api并搭建简易问答应用

《5分钟获取deepseekapi并搭建简易问答应用》本文主要介绍了5分钟获取deepseekapi并搭建简易问答应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1、获取api2、获取base_url和chat_model3、配置模型参数方法一:终端中临时将加

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制