返回   cpper编程论坛 > 技术杂烩
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

技术杂烩 找不到地方的技术问题?这里!

回复
 
LinkBack 主题工具 显示模式
  #101 (permalink)  
旧 2008-03-09
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,560
文章: 6
cat 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

嘿嘿,我不好事。
引用:
作者: sjinny
我说过了,using貌似提供的就是栈的功能,只不过语法上还不如栈简洁。
换个语言,语法上一模一样 (C++/CLI) 只是内存那个时候没有释放而已。

个人觉得资源管理,大多数也就是程序员需要指定什么时候申请什么时候释放,和程序员不需要指定什么时候申请和释放。后者显然方便,而且在后者的性能或者坏处不大的情况下会被认为是比较先进的。

对于需要指定什么时候释放的,stack/FIFO/using只能cover一些情况。还有其他情况它的生命周期是动态的,就需要分析生命周期然后去手动调用类似alloc/free的函数。这个比起完全不用管的模式要麻烦也比较容易出错。

完全不用管的模式,比如内存和CPU. 内存有gc, CPU有OS. 都不需要你写代码控制。对于CPU完全交给OS我们已经很习惯了,就是内存好像还有不少人还当宝贝一样……

现在如果把那些general的需要手动回收的资源管理全都绑定到内存上,然后放弃自动内存管理,实际上就使得内存管理重新回到一种很可能出错的状态。但就像ajoo前面说的一样,内存管理对于进程是非常重要的,不容有错。其他资源有错,你还可能完全释放后重新初始化来恢复,但内存如果access violation之类的,OS扔给你个dump就把进程杀了。所以内存管理处错的代价和其他资源是不一样的。绑定起来也没看到其他的必要性。

如果抛弃了这个绑定,stack语义的FIFO我也一直用,有啥资源的使用都尽量往上靠。但有的时候硬靠上去的代码很难维护。

引用:
作者: sjinny
我假设任何资源的生命期都只会有一次开始和一次结束。如果不符合这个假设,那么我觉得完全可以把那种生命期分解为这种结构。
这么机械的事情,编译器/执行环境/类库来做更合适。

此帖于 2008-03-09 06:26 PM 被 cat 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #102 (permalink)  
旧 2008-03-09
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
个人觉得资源管理,大多数也就是程序员需要指定什么时候申请什么时候释放,和程序员不需要指定什么时候申请和释放。后者显然方便,而且在后者的性能或者坏处不大的情况下会被认为是比较先进的。
这段话的意思,似乎你觉得一般情况下,人做的管理都比一个同样是人设计实现的、毫无智慧可言的技术差?还是说只有少数人有能力管理资源,于是他们做了gc?如果要我在人和由人所设计的东西之间选择,我会选择人,因为人所设计的东西目前还没有一样有着与人同样水平的智慧。

引用:
对于需要指定什么时候释放的,stack/FIFO/using只能cover一些情况。还有其他情况它的生命周期是动态的,就需要分析生命周期然后去手动调用类似alloc/free的函数。这个比起完全不用管的模式要麻烦也比较容易出错。
......
如果把那些general的需要手动回收的资源管理全都绑定到内存上,然后放弃自动内存管理......
固定的生存期模型的表达能力自然是有限的。你的观点*似乎*是:因为这些模型的表达能力有限,所以干脆就放弃,去寻找一种表达能力无限的模型。而我的观点是:要寻找更多的、多样化的模型来互相填补表达能力的空白。我觉得,表达能力无限的模型,意味着其对应用的假设比较少,而假设少意味着它很难进行针对性的优化。虽然假设越多,那么对使用的限制也就越多,但是当我们有了多种不同的手段时,使用它们互相配合也能解决问题,而且每个手段都能够针对它们所针对的领域进行针对的优化。
我个人的经历中,链表/数组用得比树多,度数固定的树比度数不定的树用得多……我的看法就是,因为链表/数组的约束比树强,所以虽然表达能力可能不如树,但是却更好用,因为我们知道得也多。如果是个图,而且还是个没有什么约束和约定的图,那么能够做的针对性优化就会少很多。

引用:
完全不用管的模式,比如内存和CPU. 内存有gc, CPU有OS. 都不需要你写代码控制。对于CPU完全交给OS我们已经很习惯了,就是内存好像还有不少人还当宝贝一样……
其实……OS只是负责在不同线程之间分配CPU资源,但是当你的线程拿到这些资源(或使用资源的机会)后,怎么使用它们是你自己的事情。内存也是类似的。OS只是在进程层面进行管理,而分配给你的进程的那些内存,OS就不去过问细节了,怎么使用是你自己的事情。
再说内存的确是宝贝,用户买内存也是要钱的……更何况内存的地址空间也是有限的……


引用:
现在如果把那些general的需要手动回收的资源管理全都绑定到内存上,然后放弃自动内存管理......
把非内存管理绑定到内存管理上,并不必然要求放弃自动内存管理。RAII就能把非内存资源绑定到自动管理的内存上(比如栈、内存池)。如果不能绑定(或绑定后的效果不好),我会说是这种内存管理机制的能力不够,而不会说绑定本身是错的。如果内存管理机制无法使用绑定,那么意味着使用这种自动机制就意味着要重新去做非内存资源的管理,这是在解决了一个问题(内存管理)的同时使其他问题(非内存管理)更加严重(原来还能通过RAII之类借用内存管理的一些功能,现在却不能了)。

内存管理并不是一点错都不能有,就好象如果有内存泄漏,但是不严重,那么有时可能也是可运行、可用的。而其他资源也未必那么容易管理。你也说了,其他资源的恢复也只是“可能”可以如何如何,这样内存管理也可以说“可能不是致命的错误”,比如轻微的内存泄漏。
其他资源的“重新初始化”,其实意味着在丢弃错误状态的同时也可能丢弃一些用户需要的信息。而如果其他资源的使用有错,那么可能会比内存访问出错的问题更加隐蔽,可能一直到它被实际部署时才会显露出来。
所以我也可以说,无论是内存管理还是非内存管理,都不是能够甩手不管的事情。

至于绑定的意义,我之前也说过的。
1.各种资源都有生命期管理的问题。
2.生命期管理是个麻烦的问题。要做到在最合适的时间启动生命期,并且在最合适的时间结束生命期,这是一件很困难的事情。
如果:
1.内存的生命期管理做好了
2.能够把非内存资源绑定到内存资源上
那么:
非内存资源的管理就能够借用内存管理机制中的生命期管理功能,这样生命期管理这个大麻烦就只需要在内存管理里面实现一次。
当然,如果把内存地址当成文件描述符那种抽象的资源标识,并且生命期管理是针对内存地址而不是真正具体的内存块,那么可能只需要把非内存资源绑定到内存地址上(就像把设备绑定到文件描述符上)而不需要真正绑定到具体的内存块上。
绑定的必要性就是:同样的生命期模型不应该在不同的资源管理机制中被重复实现。

说实话,如果没有绑定能力,那么各种内存管理机制对我的吸引力将大打折扣,因为我只能用它们做一件事,而本来我通过绑定能够依靠它们做更多的事的。


关于最后那些“机械的事”,你所说的“让编译器/执行环境/类库来做”,具体是指做哪些事?是做“生命期分解”,还是生命期实现,还是生命期分析,或者其他的什么?
生命期分解和生命期分析,我觉得根本上只能靠人,最多使用一些程序工具。毕竟能够真正理解需求的是人而不是程序。
生命期实现,这个*应该*是由编译器/执行环境/类库来做的。应用程序员要做的,就是在已有的各种生命期实现中进行选择和搭配。
栈是一种生命期实现,gc也是;前者能够表达的问题范围更窄,后者的表达范围更广;前者在其针对的领域内能够比较紧密地包裹对象的理想生命期,后者会有延后释放问题。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #103 (permalink)  
旧 2008-03-10
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,763
Elminster 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
这段话的意思,似乎你觉得一般情况下,人做的管理都比一个同样是人设计实现的、毫无智慧可言的技术差?还是说只有少数人有能力管理资源,于是他们做了gc?如果要我在人和由人所设计的东西之间选择,我会选择人,因为人所设计的东西目前还没有一样有着与人同样水平的智慧。
如果一件事情能够让机器管理,那么一般而言机器管理都比让人管理来得好。无它,能够让机器管理,说明这件事情是个机械的不需要智慧的事情,因此不知疲倦不会犯错的机器管理起来要强得多。

引用:
固定的生存期模型的表达能力自然是有限的。你的观点*似乎*是:因为这些模型的表达能力有限,所以干脆就放弃,去寻找一种表达能力无限的模型。而我的观点是:要寻找更多的、多样化的模型来互相填补表达能力的空白。我觉得,表达能力无限的模型,意味着其对应用的假设比较少,而假设少意味着它很难进行针对性的优化。虽然假设越多,那么对使用的限制也就越多,但是当我们有了多种不同的手段时,使用它们互相配合也能解决问题,而且每个手段都能够针对它们所针对的领域进行针对的优化。
我个人的经历中,链表/数组用得比树多,度数固定的树比度数不定的树用得多……我的看法就是,因为链表/数组的约束比树强,所以虽然表达能力可能不如树,但是却更好用,因为我们知道得也多。如果是个图,而且还是个没有什么约束和约定的图,那么能够做的针对性优化就会少很多。
这种说法太一般化了,听起来有道理,但是不结合具体问题没有什么意义。具体到内存管理这个特定的问题上,GC 就是一个足够通用的管理方式。它提供了最好的内存访问安全性保证,程序员的负担最小。你所提出的延迟释放,对于几乎所有的应用来说,并不是一个问题(这里不展开,你有兴趣我们可以另外开贴讨论)。

引用:
其实……OS只是负责在不同线程之间分配CPU资源,但是当你的线程拿到这些资源(或使用资源的机会)后,怎么使用它们是你自己的事情。内存也是类似的。OS只是在进程层面进行管理,而分配给你的进程的那些内存,OS就不去过问细节了,怎么使用是你自己的事情。
再说内存的确是宝贝,用户买内存也是要钱的……更何况内存的地址空间也是有限的……
现代的操作系统,CPU 资源都是由操作系统自己管理的。一个线程使用 CPU 足够长的时间以后,OS 会剥夺它的使用权交给其他线程。你该复习一下相关课程了,

至于内存,现在的内存不再是宝贝了。服务器多半都是 64 位系统,地址空间以 TB 记,我还没听说有哪个应用会觉得地址空间紧张。至于买内存要钱,在今天的硬件价格水平下面,这点开销不值一提。至少,如果你不用 GC 而导致延长了软件开发周期,那么你要多付的程序员工资将会数倍于 4G 服务器内存的价格。

引用:
把非内存管理绑定到内存管理上,并不必然要求放弃自动内存管理。RAII就能把非内存资源绑定到自动管理的内存上(比如栈、内存池)。如果不能绑定(或绑定后的效果不好),我会说是这种内存管理机制的能力不够,而不会说绑定本身是错的。如果内存管理机制无法使用绑定,那么意味着使用这种自动机制就意味着要重新去做非内存资源的管理,这是在解决了一个问题(内存管理)的同时使其他问题(非内存管理)更加严重(原来还能通过RAII之类借用内存管理的一些功能,现在却不能了)。
得失之间要权衡。内存管理要比其他资源的管理频繁得多,复杂得多。如果可以彻底解决内存管理问题,就算管理其他资源的时候麻烦一点,也值了。而且 RAII 在栈上使用的效果可以用 using 之类的语法糖模拟个七八成。如果能够使用我当初提出的支持手动析构的方案的话,基本上 RAII 的能力都可以保留吧。

引用:
内存管理并不是一点错都不能有,就好象如果有内存泄漏,但是不严重,那么有时可能也是可运行、可用的。而其他资源也未必那么容易管理。你也说了,其他资源的恢复也只是“可能”可以如何如何,这样内存管理也可以说“可能不是致命的错误”,比如轻微的内存泄漏。

其他资源的“重新初始化”,其实意味着在丢弃错误状态的同时也可能丢弃一些用户需要的信息。而如果其他资源的使用有错,那么可能会比内存访问出错的问题更加隐蔽,可能一直到它被实际部署时才会显露出来。
所以我也可以说,无论是内存管理还是非内存管理,都不是能够甩手不管的事情。
内存访问违例可以直接让你这个进程完蛋,其他资源访问出错都没有这么猛的效果。至于你说“而如果其他资源的使用有错,那么可能会比内存访问出错的问题更加隐蔽”,你倒是举一个例子出来?什么错误能够比往内存中写数据的时候写到相邻的另外一个对象里去这种错误更隐蔽,更难重现?

引用:
至于绑定的意义,我之前也说过的。
1.各种资源都有生命期管理的问题。
2.生命期管理是个麻烦的问题。要做到在最合适的时间启动生命期,并且在最合适的时间结束生命期,这是一件很困难的事情。
如果:
1.内存的生命期管理做好了
2.能够把非内存资源绑定到内存资源上
那么:
非内存资源的管理就能够借用内存管理机制中的生命期管理功能,这样生命期管理这个大麻烦就只需要在内存管理里面实现一次。
当然,如果把内存地址当成文件描述符那种抽象的资源标识,并且生命期管理是针对内存地址而不是真正具体的内存块,那么可能只需要把非内存资源绑定到内存地址上(就像把设备绑定到文件描述符上)而不需要真正绑定到具体的内存块上。
绑定的必要性就是:同样的生命期模型不应该在不同的资源管理机制中被重复实现。

说实话,如果没有绑定能力,那么各种内存管理机制对我的吸引力将大打折扣,因为我只能用它们做一件事,而本来我通过绑定能够依靠它们做更多的事的。
问题就在于不同的资源的生命周期管理起来方式大不一样,它们根本就不是“同样的生命期模型”。你自己比较一下线程和文件,看看这两种常见的资源的生命期管理有什么地方是一样的?它们唯一的共同点只有都需要分配、都需要释放,除此之外就没多少交集,干嘛要把这些不相干的东西都塞进内存管理这个框里?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #104 (permalink)  
旧 2008-03-10
普通会员
 
注册日期: 2003-08-25
帖子: 80
fixopen 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

我觉得sjinny其实并不是对filo式的内存管理模式感兴趣,或者并不是仅仅对它感兴趣。sjinny可能是对lexical scope这类模式感兴趣,希望能把lexical scope应用到尽可能多的场合,尽可能多的资源种类上。

但是实际上,在我的感觉中,内存这种资源是所有资源中管理最复杂生命周期最有弹性的资源了。用filo管理别的资源或许还比较合适,管理内存就有点吃力了。

另外,sjinny说的{}比using的方式语法更简洁,这也只能应用在内存这种资源上,对于别的资源,我相信由于千差万别的释放资源的手法导致写出来各式各样的析构不一并比Disposing模式+Using语法简洁多少。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #105 (permalink)  
旧 2008-03-10
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

唉,今天的麻烦太多,心情十分不爽……

to Elminster:
1.永远都不会有富余资源,因为我们无法假设用户在使用我们的软件的同时不会想要使用其他软件做其他事……
2.硬件发展永远不会足够,因为当硬件性能增长了10%时,用户需求会增长得比10%更多。现在的硬件比起几十年前要强劲得太多,但是对于那些主流游戏,有多少电脑能够一直使用最佳的画质?对于那些常用软件,有多少在启动时完全不需要用户等待?无论是浏览器、office套件还是娱乐软件之类之类……有多少大型软件在出新版本时不需要用户升级硬件也能获得跟以前一样的性能?更何况很多普通用户没有能力或兴趣来优化自己的电脑……
3.我不需要复习也知道抢占,但是这只是在线程之间的协调机制。当你的线程获得了一定的时间片后,如何使用它是你自己的事情,相信这不需要复习也不难理解。
4.如果只看服务器而不看桌面电脑,那我也可以指着超级计算机说:“因为有这样的东西存在,所以任何软件优化都是多余的”。更何况及时在超级计算机上,软件优化也是很重要的。硬件的发展是为了让用户做更多的事情,而不是为了让软件开发人员挥霍。
5.是否不使用gc就必然延长开发周期?是否使用了gc就必然缩短开发周期?是否使用了gc就不仅能必然缩短开发周期而且还必然不带来其他副作用?
6.在我看来,内存管理的麻烦的根源就在于生命期模型。如果有个机制能够确保在内存块的生存期结束时就*一定*、*准时*调用我所指定的行为,并且对这行为没有太多限制,那么内存管理还有什么难处呢?特别是对于应用程序,剩下的无非是内存池之类之类的,这和其它非内存资源的管理比起来又能困难多少?
7.不知道那些设计gc的人有没有信心说“彻底”解决内存管理问题。
8.如果某个非内存资源是信用卡读写器(哪怕只是使这张卡作废也会让用户恼火的),如果某个非内存资源是指向某个机密数据库的连接,如果某个非内存资源是指向某个人的照片目录的文件描述符而错误的访问导致其内容被发送至网络或打印机……
9.如果某些网络连接管理出错,导致不同用户之间的数据包的混乱,那么可能多个用户的账户信息会被搞乱,而这在运行时不会有什么明显的征兆。如果内存访问导致程序崩溃,大多数用户只会习惯性地重启软件,可是其他方面的正确性用户往往不会每次都检查的……如果你能保证软件交付给用户后100%不出问题那当我没说。
10.“它们唯一的共同点只有都需要分配、都需要释放”。这就是关键:如何确保在最合适的时机执行“分配”?如何确保在最合适的时机执行“释放”?如何确保这些行为在一次生命周期中被执行一次且仅一次?如何确保在“分配”前和“释放”后的访问都会导致一次可控的异常抛出而不是整个系统挂掉?而无论是内存管理还是非内存管理,这些都是最大的麻烦(我不知道有没有“之一”)。如果你觉得非内存资源的管理不重要那当我没说。
11.析构函数最大的好处在于:它会被自动调用。如果把这个特性去掉了,那跟普通函数还有什么区别?貌似Dispose还比这种“析构函数”强点。using这种办法来实现RAII,其实是使用一种特定的方法来解决特定的问题(即实现RAII)。现实世界的复杂度太高,所以我们需要的是能够有一定程度的通用性的手段。


to fixopen:
的确,某个具体的内存管理方法是否是FILO的对我来说一点都不重要。重要的是能不能找到足够多的方法,并且它们能够用彼此的长处填补彼此的空白,从而形成一个有足够覆盖力的工具集。
我不太清楚“lexical scope”的确切含义。如果是特指栈,那么我要说我并不是想把栈用于一切。如果是泛指语法层面的模式,那么我要说我要的不仅是语法上的简洁有效,我同时也需要其背后的机制简洁有效。所以在栈和using这两者之间,我更喜欢栈。
就像我在上面to Elminster的10中所说,内存管理和其它非内存资源的管理的最大的麻烦来源之一就是生命期管理,而且现在普遍使用的生命期模型都是“分配-释放”这种最最简单的模型。所以在我看来最最关键的只是生命期问题,至于生命期结束时如何把内存还给系统这种事情并不是最大的麻烦。而生命期问题是多种资源管理的共同的问题。
至于FILO,那只是多种工具中的一种,我不记得哪个帖子里想要用它解决所有问题过,我只记得我说过很多次,这玩意的表达力有限,所以需要更多的工具来覆盖表达力盲区。
有一点我要强调:我寻求栈意外的管理手段是因为栈的表达力有限,它在它的覆盖范围之外的效果不好。如果能够使用using,那么也能够使用栈;如果能够使用栈,那么应该也能够使用using。但是问题在于,当无法使用栈的时候,能使用using吗?我觉得不能,因为不能使用栈的情况一般是程序员对生命期模型的了解不是很清楚,或者生命期模型与栈不相容。我要的是除了栈意外的、同样优秀但是表达力有所不同的工具,using不是这样的工具。我不想再争执“栈和using哪个更好”这个问题,因为这不是我最主要的问题。但是我还是要解释一下,我说using没有栈简洁,是因为使用栈时只需要使用花括号,而不需要按using这么多键。就像“x+y”这个式子比“横坐标加上纵坐标”这句话更简洁一样。



这个长贴再一次让我对一个问题加深了认识:“人与人的沟通是很困难的。”
我很多回帖都是在不断地解释大家对我的误解,而我真正想讨论和解决的问题却一直没有进展,也许我的表达能力实在太糟。

此帖于 2008-03-10 05:51 PM 被 sjinny 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #106 (permalink)  
旧 2008-03-10
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,560
文章: 6
cat 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

我印象比较深的是你上来就bs GC但GC是我见过最舒服的内存管理方式了。

管理对象生命周期的模式不少,但各不相同。自动释放也是其中一种,很方便,但实现起来却有难度,特别是对于内存这种对性能要求极高的东西。但由于内存管理太重要了,前人也画了太多的代价在上面,因此还是有人做出了在工业上可用的GC.

硬件的发展是会造成区别的。为什么DOS不支持多任务而UNIX上手就是进程模型?因为PC的CPU不够强劲。不知道Windows 3.1只有合作式是不是也有类似的考虑。当CPU足够强劲,允许OS每10毫秒来干涉一下的时候优雅的枪战式多任务就占了上风:稳定不死机,客户代码也无须管什么时候释放CPU资源。这其实就使得CPU资源从需要显示被释放变成了自动被释放。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #107 (permalink)  
旧 2008-03-10
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
作者: sjinny 查看帖子

这个长贴再一次让我对一个问题加深了认识:“人与人的沟通是很困难的。”
我很多回帖都是在不断地解释大家对我的误解,而我真正想讨论和解决的问题却一直没有进展,也许我的表达能力实在太糟。
不是你的表达能力太糟,是你的基础知识实在太糟,lexical scope, 副作用这些大家讨论的基本词汇你居然都不懂,就象一个人一本正经地跑去跟人家讨论物理,质疑相对论,最后居然发现把“加速度”当作两个速度相加...

还有你的逻辑也很让人看不懂,不经证明地抛出一大堆的论断,“我认为”,“我觉得”就不说了。前面你还质疑优化呢,还承认自己对优化不懂呢,这又开始强调优化的重要性了。还有,攻击gc的效率,确定性什么的倒也罢了,本来就是争议性的问题,但是什么软件的可维护性,对变化的适应性,这本来都是gc的长处,居然到你这里不经解释直接拿过来就成你的武器了,真是让人不由得纳闷“这都从何说起的呢?”

要说这个坛子是你最可能找到同道,大家一起捍卫destructor,声讨gc的,可惜呀,这些固执的量子时代的爱因斯坦们可能实在不好意思附和某些同志,因为这个同志有点太象gc这个敌人那边的托儿了——犯所有能犯的低级错误,除了make sense的什么都说。

此帖于 2008-03-10 10:29 PM 被 ajoo 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #108 (permalink)  
旧 2008-03-11
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 843
文章: 7
bankrock 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

其实这里反对GC的人未必多,主要还是考虑效率问题,如果0x引入GC被证明对效率影响不大,那我也就拿来用了。要是那天有出来个语言能支持00和GP这两个范式,语法紧凑而且写出来的程序跑的滴溜溜转,管他GC不GC,我第一时间叛逃C++阵营。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #109 (permalink)  
旧 2008-03-11
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

NND,我哪句话把“软件的可维护性、对变化的适应性”与gc联系起来了?都是因为谈到了静态代码分析的问题,我才说有些东西不显式表达的话是没法再自动分析出来的,会有信息丢失。一个主题里的回帖并不一定都是针对顶楼的帖子或者标题的,我那些针对的是前面的静态分析的话题。

“lexical scope、 副作用”这些是术语,我没见过这个术语不代表我不理解其实际所指的含义。只不过我看过太多讨论因为概念和定义上的不一致而引发不必要的争执,所以我才要问。如果真的要讨论,就要愿意解释自己的想法和概念;如果懒得解释,那就不要说。

要说证明,不知道这里谁的帖子有“证明”?都是结论对结论,我就不能这么做?再说,关于gc的缺点问题,关于静态分析的问题,我都有自己的理由和解释。


我知道,每次我回帖里写得那么多,真正能够一字不拉地看下来的人没几个。看看我的帖子的字数和你们帖子的字数就能看出来,我对我的想法能够写这么多来解释,你们就可以抛出几个术语然后不闻不问?如果不想讨论就不要来搀和,想讨论就要有诚意。如果只是想证明我如何如何不好,那你们不用证明了,我自己知道自己的缺陷。

NND,没有诚意就不要摆高姿态来教训人。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #110 (permalink)  
旧 2008-03-11
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,763
Elminster 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
to Elminster:
1.永远都不会有富余资源,因为我们无法假设用户在使用我们的软件的同时不会想要使用其他软件做其他事……
这一条没什么意义,如果用户一定要在玩 WOW 的同时开 Photoshop 做滤镜同时开 3DMAX 做渲染同时开 MATLAB 跑科学计算,谁也救不了这个用户。开发任何一个软件,我们都必须划条线,假设它能够得到多少资源,在这个框架之下工作,而不是不顾一切地把资源消耗往下压。

引用:
2.硬件发展永远不会足够,因为当硬件性能增长了10%时,用户需求会增长得比10%更多。现在的硬件比起几十年前要强劲得太多,但是对于那些主流游戏,有多少电脑能够一直使用最佳的画质?对于那些常用软件,有多少在启动时完全不需要用户等待?无论是浏览器、office套件还是娱乐软件之类之类……有多少大型软件在出新版本时不需要用户升级硬件也能获得跟以前一样的性能?更何况很多普通用户没有能力或兴趣来优化自己的电脑……
这个问题确实存在,但你得分清楚硬件的瓶颈在哪。主流游戏不能用最佳画质,是内存不够的问题吗?大型软件启动时候需要用户等待,是内存不够的问题吗?相信不用我来多说吧?

引用:
3.我不需要复习也知道抢占,但是这只是在线程之间的协调机制。当你的线程获得了一定的时间片后,如何使用它是你自己的事情,相信这不需要复习也不难理解。
这就是偷换概念了。我们讨论的问题是“CPU 这个资源由谁来管理”,对不对?你的线程既不能决定什么时候能够获得 CPU 运行,也不能决定自己什么时候被其他人抢占,所以 CPU 完全是由 OS 管理的,程序员没有控制权,这话没错吧?

引用:
4.如果只看服务器而不看桌面电脑,那我也可以指着超级计算机说:“因为有这样的东西存在,所以任何软件优化都是多余的”。更何况及时在超级计算机上,软件优化也是很重要的。硬件的发展是为了让用户做更多的事情,而不是为了让软件开发人员挥霍。
不要把我的观点推向极端。我没说不需要做优化,但是你要弄清楚瓶颈在哪里,什么地方是值得做优化的。看看如今的 PC 就知道了:对于 99% 的用户来说,不能做更多事情的硬件瓶颈,是内存吗?

引用:
5.是否不使用gc就必然延长开发周期?是否使用了gc就必然缩短开发周期?是否使用了gc就不仅能必然缩短开发周期而且还必然不带来其他副作用?
从统计意义上讲,就是这样没错。

引用:
6.在我看来,内存管理的麻烦的根源就在于生命期模型。如果有个机制能够确保在内存块的生存期结束时就*一定*、*准时*调用我所指定的行为,并且对这行为没有太多限制,那么内存管理还有什么难处呢?特别是对于应用程序,剩下的无非是内存池之类之类的,这和其它非内存资源的管理比起来又能困难多少?
这话忒外行了。内存管理的难点,从来都是如何杜绝悬挂引用和内存泄漏,前者导致程序崩溃,后者“挥霍宝贵的内存资源”,根本不是什么“在内存块的生存期结束时就*一定*、*准时*调用我所指定的行为”。GC 真正的价值,就是在很大程度上解决了这两个问题,从而上程序员可以放心的运用更多能够提高生产力的技术。

引用:
7.不知道那些设计gc的人有没有信心说“彻底”解决内存管理问题。
没有任何技术可以“彻底”解决内存管理问题。

引用:
8.如果某个非内存资源是信用卡读写器(哪怕只是使这张卡作废也会让用户恼火的),如果某个非内存资源是指向某个机密数据库的连接,如果某个非内存资源是指向某个人的照片目录的文件描述符而错误的访问导致其内容被发送至网络或打印机……

9.如果某些网络连接管理出错,导致不同用户之间的数据包的混乱,那么可能多个用户的账户信息会被搞乱,而这在运行时不会有什么明显的征兆。如果内存访问导致程序崩溃,大多数用户只会习惯性地重启软件,可是其他方面的正确性用户往往不会每次都检查的……如果你能保证软件交付给用户后100%不出问题那当我没说。
我从来没说过非内存资源的管理不重要,我说的是非内存资源管理起来难度要低得多。而且,你这里的描述,例如“如果某些网络连接管理出错,导致不同用户之间的数据包的混乱”,和网络连接管理有关系么?网络连接管理负责建立和拆除网络连接,读进来的数据包怎么处理,会不会弄乱,也属于网络连接管理的范畴?

…………

也累了。以后再说吧。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #111 (permalink)  
旧 2008-03-11
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

1.我不愿意对用户做什么假设或者限制,或者至少要尽量减少这种限制。

2.在新游戏的内存要求都达到1g的现在,在很多电脑都需要使用虚拟内存的现在,内存真的嫌多了吗?

3.
代码:
int main() { while(true); return 0; }
这段代码在机器空闲时会让CPU占用率升到近100%,如果开了很多的线程都在这样使用CPU那会怎么样?OS如何知道这不是用户的意愿而自动调低优先级?毕竟3D渲染之类的应用正常情况就是这样,而另一些应用的正常情况是不应该这样的,OS能自己解决这种问题吗?而很多用户连优先级的意义都搞不清楚。做游戏的时候,入门的代码经常都是这样使用CPU的,之后才会解决控制帧率的问题,才会解决帧与帧之间通过sleep来减少CPU占用。

4.我这么说是因为你前文再拿4G内存来比较,而对于PC上的应用就不能这么比较了。现在还有很多机器用着512M甚至256M的内存。

5.你所说的“统计意义”的统计范围是哪些呢?一个软件类型算一个样本点,还是按照软件数量来算样本点?

6.
悬挂引用:当还有指针指向某块内存时,这块内存就处于“被需要”的状态,这时释放它就会出问题,这是“过早释放”的问题。
内存泄漏:这是“过晚释放”的问题,毕竟现在大多数操作系统都能回收进程的内存资源,所以没多少内存是永远不会回收的,只不过一般回收得太晚而已。
生命期管理,就是在“合适”的时间执行“分配”和“释放”这两个概念所对应的行为。生命期管理机制的责任在确保在“合适”的时间来调用指定的行为,而具体的分配和释放行为由这个机制的使用者来制定。这里的“合适”的时间,就是要使实际的“分配”和“释放”时间尽量紧密地包裹资源的理想生命期。实现了这样的生命期管理机制之后,无论是内存管理还是其他资源管理,其难点在哪?这样的机制是否就是对应着最麻烦的问题?

7.我那个“彻底”针对的是“如果可以彻底解决内存管理问题,就算管理其他资源的时候麻烦一点,也值了。”这句话。我自己没有认为“有技术可以“彻底”解决内存管理问题”。

8.
“如果可以彻底解决内存管理问题,就算管理其他资源的时候麻烦一点,也值了。”
“内存访问违例可以直接让你这个进程完蛋,其他资源访问出错都没有这么猛的效果。至于你说“而如果其他资源的使用有错,那么可能会比内存访问出错的问题更加隐蔽”,你倒是举一个例子出来?什么错误能够比往内存中写数据的时候写到相邻的另外一个对象里去这种错误更隐蔽,更难重现?”
我那些例子针对的是这几句话。特别想说明的就是的确有些非内存资源的错误会导致比“进程完蛋”更严重的后果,比如用户宁愿经常重启软件也不想自己的数据被破坏(如果不得不在两者间选择的话)。

至于网络连接,比如说网络模块封装了绝大多数的网络操作,而为了封装,网络模块不会把内部的Connection对象的地址泄露到模块外去,因此传出去的都是ConnectionID(一个int),内部用一个hash表映射到Connection对象。而这些ID也是需要管理的,如果管理出错,就会产生错误的映射,而把针对一个连接的操作应用到另一个不相干的连接上。
这种模式在管理其它东西时都可能用到(为了模块的封装性),这里的Connection可能会变成任何其他资源:文件,数据库接口,mutex,硬件的访问接口,或者其他东西。
而“读进来的数据包怎么处理,会不会弄乱”的确属于网络连接管理的范畴,至少在我这里是的,因为我希望网络模块把网络操作尽量封装好,外部使用时不需要针对“网络”这个概念进行太多针对性的操作。所以我的网络模块与上层之间传递的都是消息对象,网络模块负责消息的广播、序列化/还原,还负责调用预处理接口(这里相当于有两次process()的Command),预处理里可能会有加密/解密以及压缩/解压缩,最终上层用的时候就像与本地模块通信那样交换消息对象。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #112 (permalink)  
旧 2008-03-11
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
这一条没什么意义,如果用户一定要在玩 WOW 的同时开 Photoshop 做滤镜同时开 3DMAX 做渲染同时开 MATLAB 跑科学计算,谁也救不了这个用户。开发任何一个软件,我们都必须划条线,假设它能够得到多少资源,在这个框架之下工作,而不是不顾一切地把资源消耗往下压。
也许现在看起来这是无意义的,但是如果用一种技术把各种产品连接起来,直接把PS的滤镜功能与3D Max的贴图处理连接起来,而把Matlab计算的定点坐标输入给3D Max,然后用这些软件联合做一些艺术创作,这样是没有意义的吗?这样用户在三个显示屏的支持下可以获得一个很好的创作环境,在PS中绘制贴图,在3D Max里就会实时看到作为贴图的渲染效果,而Matlab则在给3D Max提供复杂曲面算出的模型顶点信息,并且以动画的形式在3D Max里渲染出来给用户看……



另外想起来,对于很多用户来说,在笔记本上一边开QQ、一边开浏览器、一边放音乐、一边玩大型游戏,而且还开着防火墙、杀毒监控软件,甚至还在开着下载软件……这对于他们仍然算是正常的应用状态,因为他们要一边抽空用qq聊天,一边用浏览器看游戏攻略,一边听音乐,一边玩游戏,一边顺便下载点电影……
如果这些软件都不控制对资源的消耗,结果就是用户做不了自己想做的事情。更何况很多人的windows不仅没有优化配置,而且还开着很多界面特效、用着华丽的主题……

此帖于 2008-03-11 02:42 PM 被 sjinny 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #113 (permalink)  
旧 2008-03-11
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,560
文章: 6
cat 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

引用:
作者: sjinny
要说证明,不知道这里谁的帖子有“证明”?都是结论对结论,我就不能这么做?
貌似许多人带有一些所谓的common sense, 也就是那这东西可以说是不证自明的论据,或者说已经被实践证明了的(比如,GC对于开发周期的帮助)。但是到你那里这里就成了“结论对结论”了,所以才会觉得比较累。

回到资源管理,我觉得资源管理话题太大,scenario之间的区别也太大,统一的方法论是不现实的。但是其中确实有类似的,比如有些是有显示的范围的,由一些适合用一个pool, 由一些则可以完全自动化这些现有的技术已经足够用了。给出一个特定的资源管理问题,或者可以直接套上上面的模式,或者就不得不由分析来得出一套自己的管理模式,而这种情况下通用性一般都不大(通用性大的话,会被抽出来做成一个模式)。由一些需求就是很“人性化”的,比如电话线路的资源管理的周期控制,是事件触发的:对方挂电话,或者无人接听达到1分钟,或者出现异常断线等。相信针对上面的情形写个代码来管理很多人都会,要说把它推广到普通情况,比如UI的窗口管理也是事件驱动的,那么剩下来的公共代码其实并不多,价值也不大,反而会有一些对于那种硬抽出来的东西的“学习曲线”,得不偿失。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #114 (permalink)  
旧 2008-03-11
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

原来你们不证明是因为你们的观点是“不证自明”的……那我是不是可以理解为,因为你们认同自己的观点,所以你们不需要证明自己的观点;因为你们不认同我的观点,所以我需要证明我的观点?这样的逻辑就不是讨论的态度,是争执的态度。争执就是说服与被说服的关系,讨论是获得新知的过程。
我们寝室里在讨论问题的时候,至少不会有谁说自己的观点是“不证自明”的……哪怕是教科书,里面的观点也不会这么说……在数学里,“不证自明”的公理也是尽量要定理化的……
希望只是我误解了cat的意思……


我已经重复了很多次很多次很多次了:各种资源管理的共同点之一就是生命期管理。生命期管理的失误会导致分配和施放的实际执行的时机不合适,过早释放导致野指针,过晚释放导致内存泄漏,而这两个问题恰恰是难点。
我从来都没想要用一种一成不变的办法来完全解决大量不同的问题。但是,虽然没有方法能够完全解决大量不同的问题,但是这不代表不存在一种方法能够解决大量不同问题中的共同的那部分。各种资源的确有所不同,但是生命期管理是共同的内容,也是最难、最关键的内容(不知道是不是“之一”)。
生命期管理并不一定是显式指定生命期边界的管理方法。无论是引用计数还是scope,这都是具体的方法,但它们都是生命期管理。
对于事件驱动,我假设一般都会存在一个机制来把行为绑定到事件上:比如回调,比如消息,比如轮训……总之能够在发生事件时调用我制定的行为。实际上如果只是“挂电话”这种事件,那么由于事件很容易分辨,所以很容易就把资源释放与事件绑定起来。但是对于“最后一个指向该内存块的指针改变了指向”这种事件,就不那么容易分辨:为了分辨这一事件,使得引用计数不得不使用一个额外的数据来记录引用的数目,多线程环境下的问题也是由这个额外的东西(的访问和维护)引起的。
如果你说的“要说把它推广到普通情况”的含义是指“用上面的事件所对应的管理代码来管理UI里的资源”,那我要说我一直强调的我所认为的共同的问题并不包括这些:这些里面主要都是生命期边界上所调用的行为,而不是生命期边界本身的确定和触发机制,而剩下的消息机制则的确是通用的东西。


我想还是一个问题一个问题的来吧:
目前我想了解的是大家对这个问题的看法:
当找到了一个或一组机制,能够比较好地解决生命期管理的问题后,这样的机制对各种资源的管理是否有很大的帮助?
这里的“生命期管理”是指:
能够按照使用者的要求,把使用者所指定的“分配”行为和“释放”行为绑定在被管理对象的生命期边界上。
1.管理机制对使用者所指定的分配行为和释放行为没有太多约束
2.管理机制确保将会按照使用者所描述的理想生命期边界上调用一次且仅一次。
3.管理机制能够提供充足的方法,让使用者选择和组合这些方法,以获得能够覆盖绝大多数生命期模型的表达力,因此这些不同的方法之间应该是尽量正交的。
这里的生命期边界指“生命期开始”或“生命期结束”这样的时机。而使用者将根据自己所能够获得的信息,向管理机制描述被管理对象的生命期模型。这里的被管理对象,可以是内存块,也可以是任意概念(比如对象、ID值、mutex、文件描述符等)。
现有机制的状体:
栈:符合1,接近2(栈对生命期的包裹一般是“比较紧密的”,只不过距离理想的程度还有小小的距离),不符合3(虽然栈能够与其他机制配合,但是其自身的表达力很有限,所以只能作为多种方法中的一个)。
内存池:符合1,接近2(内存池的包裹程度比栈还要松散一点,但是这经常也是因为程序员对生命期掌握的程度比较低,所以才选择内存池而不是栈),不符合3(同栈)
智能指针:符合1,很接近2(如果能把各种事件和条件良好地映射到智能指针的持有和丢弃上,那么生命期包裹还是很紧密的),接近3(表达力比栈和内存池更强,但是对于以特定条件或事件的组合来确定生命期边界的情况没有提供直接的支持,有时可能需要手动用智能指针对象来把事件映射到生命期管理中)
gc:不符合1(毕竟gc*经常*是应用线程之外的独立线程,而且collect的时候还需要停止应用线程的工作[至少要暂停对被collect的内存区域的访问],当然更重要的还是时机的不确定性,所以限制会多一些),不符合2(主要的问题是延后释放使得生命期包裹不紧密),接近3(其实这个方面的问题跟智能指针是类似的——某些生命期模型下需要使用者自己做一些从事件到管理的映射)。

如果想讨论资源管理,我建议从以上这个问题开始。

此帖于 2008-03-11 09:30 PM 被 sjinny 编辑.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #115 (permalink)  
旧 2008-03-11
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,560
文章: 6
cat 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

每做一道数学题都需要从自然数的构造开始恐怕就做不下去了吧。一样,讨论也是有一定的公共基础的。只是说你和很多人的“公共基础”有很大距离导致了沟通困难。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #116 (permalink)  
旧 2008-03-11
sjinny 的头像
普通会员
 
注册日期: 2008-02-01
帖子: 66
sjinny 正向着好的方向发展
默认 回复: 请教各位大大关于动态内存管理的问题……

首先,每一道数学题里,你所使用的根据要么得是公理,要么得是定理,而不能是“不证自明”的东西。公理在我看来更像一种假设,即“假设现实是这样的”,而定理则是在这个基础上推导出来的。

讨论的确要有公共基础,但是如果不愿意向别人解释自己所认为的“公共基础”,那就是缺少诚意的表现。更何况很多时候并不是别人不懂你所指的某些东西,而只是你的符号系统与别人不完全一样,需要一个映射的过程。如果讨论时不愿意明确概念,那也是个态度问题。如果讨论时喜欢用自己的理解来定义别人的概念,那就没有交流的心态,而是始终从自己的视角去评判别人而不愿真正去理解别人。

不理解你的符号不等同于不理解你的符号所代表的事物。
Digg this Post!Add Post to del.icio.us