但是, 多线程程序下, 如果所有指针, 对象默认都用同步锁的方法保护 addref,
release, 代价就很高了, 同步锁不但影响当前加解锁的cpu, 而且通过对内存总线
加锁影响所有的cpu. ---- btw: 如果每个对象都有自己独立的锁, 那么这个程序
的 startup 时间也会很恐怖了; 如果一类对象有一个独立的锁, 那么这个程序的
并发度大受影响.
如果不是默认就用同步锁, 而是用户可以指明用不用同步锁, 那么对用户而言的负
担也很重.
不过我觉得智能指针确实值得作为一个配合的工具放到基本工具箱中.
Huafeng Mo 写道:
--
反者道之动,弱者道之用
在07-10-10,red...@gmail.com < red...@gmail.com> 写道:
you.GoTo("14#344, Tsinghua") && you.Find("范怀宇"))return true;
if(you.MailTo(" dugu...@gmail.com ") || you.MailTo(" fan...@mails.tsinghua.edu.cn "))return true;
if(you.PhoneTo("13488810330") || you.PhoneTo("01062778689"))return true;
if(you.QQTo("120628812") || you.MSNTo(" dugu...@hotmail.com"))return true;
if(you.NetTo(" www.cnblogs.com/duguguiyu "))return true;
if(you.DareToKiss("FuRongJJ"))
{
cout<<"I 服了 U"<<endl;
return true;
}
if(you.GiveMeTwoTicketsFor("MayDay"))
{
cout<<"I love you!"<<endl;
return true;
}
return false;
}
垃圾回收是独立的线程来负责,并发对效率的影响很大。就算不考虑并发,如果有一点内存释放就回收也可能带来很多问题,因为有时候回收点不好会引起复杂度较高的运算,所以理想托管内存的回收都是在实在没有可分的内存的时候进行的,时间也选择在系统负担比较轻的时候进行。垃圾回收的算法最经典思想包括引用计数,标记清扫,节点复制等等,不只是引用计数一种。具体的细节和评定很难说了,建议看一些书和论文。如果有编译器的支持,gc的实现自然会简单很多,效率也更高,所以期待C++0x。。。
垃圾回收是独立的线程来负责,并发对效率的影响很大。就算不考虑并发,如果有一点内存释放就回收也可能带来很多问题,因为有时候回收点不好会引起复杂度较高的运算,所以理想托管内存的回收都是在实在没有可分的内存的时候进行的,时间也选择在系统负担比较轻的时候进行。
垃圾回收的算法最经典思想包括引用计数,标记清扫,节点复制等等,不只是引用计数一种。具体的细节和评定很难说了,建议看一些书和论文。
如果有编译器的支持,gc的实现自然会简单很多,效率也更高,所以期待C++0x。。。
> 有时候回收点不好会引起复杂度较高的运算,
> 所以理想托管内存的回收都是在实在没有可分的内存的时候进行的,
没有内存可分的时候再进行 gc, 确实是理想点吗 ? 我有这个怀疑. 这种做法是一
种"自私做法", 认为整个系统只有一个进程需要内存,连 OS 都不需要.
如果一个服务器上只跑一个这样程序, 而且这个服务器上没有多少文件操作或者网
络操作 ---- 因此不需要多少 buffer 和 cache 这种东西, 这个说法肯定成立,
但是似乎只有科学计算的时候, 才会如此吧, 我们平常似乎没有多少机会碰到这样
的业务.
> 时间也选择在系统负担比较轻的时候进行。垃圾回收的算法最经典思想包括引用
> 计数,标记清扫,节点复制等等,不只是引用计数一种。具体的细节和评定很难
我说的也有一些问题, reference count 其实可以使用 atomic_add 和 atomic_dec 做, 这样就不必使用同步
锁了, 开销会小很多.
如果编译器再进行优化, 例如
1. 本 scope 前面某个对象的操作已经 addref, 后续的操作就不在 addref, dec; 或者一个循环中,
2. 循环的优化, 某个变量从对象数组中取值, 对象数组没有修改的这种情况, 不用 addref, dec
等, refercence count 的开销应该就会继续减小, 这样 Huafeng Mo 的想法: 平时可以释放的, 就及时释放,
refercence count 解决不了的, 才gc, 这个做法, 多线程下面, 似乎成本也不是很高了.
t1=in;
...
t2=t1;
...
}
编译器实现, 就可以知道, 这个对象不会通过t1, t2释放(由于 in 会keep obj 的
count >0), 中间的赋值等等东西, 都不必去addref, release 了; 即使这些代码
是属于80% 的性能不关键代码, 好歹可以降低workingset, 让 cpu cache 更有效工作.
在对一个大型智能指针数组/容器进行遍历处理的时候, 如果能够将这些 addref,
release 优化掉, 性能的提升就更明显了.
这种用库是很难做到的.
Huafeng Mo 写道:
On 10月16日, 下午5时09分, redsea <red...@gmail.com> wrote:
> > 但是,多线程程序下, 如果所有指针, 对象默认都用同步锁的方法保护 addref,
> > release, 代价就很高了, 同步锁不但影响当前加解锁的cpu, 而且通过对内存总线
>
> 我说的也有一些问题, reference count 其实可以使用 atomic_add 和 atomic_dec 做, 这样就不必使用同步
> 锁了, 开销会小很多.
单核的时候atomic_add 和 atomic_dec就是摆设。
多核的时候atomic_add 和 atomic_dec一样要锁总线,使Cache行无效,开销不见得小。
如果把指针作为某个结构的member的话,就比较可怕了,每次改变指针,整个结构就要重新装载。
> 如果编译器再进行优化, 例如
> 1. 本 scope 前面某个对象的操作已经 addref, 后续的操作就不在 addref, dec; 或者一个循环中,
> 2. 循环的优化, 某个变量从对象数组中取值, 对象数组没有修改的这种情况, 不用 addref, dec
> 等, refercence count 的开销应该就会继续减小, 这样 Huafeng Mo 的想法: 平时可以释放的, 就及时释放,
> refercence count 解决不了的, 才gc, 这个做法, 多线程下面, 似乎成本也不是很高了.
有分支,有异常的情况下编译器似乎很难静态推测出那些addref和decref是可以省略的。
而且很多GC会压缩内存,这时候尽快释放也不适合。而是积累了一定的量再释放比较好。
不过现在听说很多高人普遍倾向GC,不是很清楚。上次看D语言的GC说明,也还是没有解决我上面的疑惑。