[入门] 有人关注mono吗?

oldrev 2009-08-25
JIT 优化的空间还很大,甚至可能超过完全静态编译的 native 代码,抛开速度不说,其实 VM 语言的主要缺点是内存占用比 C/C++ 大太多了。
codekitten 2009-08-25
oldrev 写道
JIT 优化的空间还很大,甚至可能超过完全静态编译的 native 代码,抛开速度不说,其实 VM 语言的主要缺点是内存占用比 C/C++ 大太多了。


很理想,但是对于GUI来说,JAVA和C#都做的不好
tomqyp 2009-08-25
oldrev 写道
JIT 优化的空间还很大,甚至可能超过完全静态编译的 native 代码,抛开速度不说,其实 VM 语言的主要缺点是内存占用比 C/C++ 大太多了。


为什么VM 语言内存占用大呢?
RednaxelaFX 2009-08-25
tomqyp 写道
oldrev 写道
JIT 优化的空间还很大,甚至可能超过完全静态编译的 native 代码,抛开速度不说,其实 VM 语言的主要缺点是内存占用比 C/C++ 大太多了。


为什么VM 语言内存占用大呢?

oldrev老大想说的可能是“GC语言的主要缺点是内存占用比C/C++大太多了”。GC要有效的工作,会需要比较大的“剩余空间”,特别是像copying-collector那样的。现在常用的GC算法主要是基于跟踪(tracing)的,这些算法都是在分配的空间越多(剩余空间越小)的时候效率越低……
tomqyp 2009-08-25
从我这段时间的使用经验,以及一些language shootout来看python比java和.net的内存占用小不少,这又是为什么呢?
tomqyp 2009-08-25
我觉得动态语言本身的特性是个主要原因,把一个稍微复杂点的事物抽像出来用.net或者java来描述,可能要把一个基类派生好几层才能把事说的清楚。动态语言就灵活方便的多,附带的也省掉不少内存开销。
codekitten 2009-08-26
tomqyp 写道
我觉得动态语言本身的特性是个主要原因,把一个稍微复杂点的事物抽像出来用.net或者java来描述,可能要把一个基类派生好几层才能把事说的清楚。动态语言就灵活方便的多,附带的也省掉不少内存开销。


时间换空间,空间换时间
mathgl 2009-08-26
python的gc是 最简单的 reference counting..是耗不了什么资源。。

调用c lib也简单。比java好多了。。jni还得留神一不小心弄个crash就头大了。
RednaxelaFX 2009-08-26
tomqyp 写道
我觉得动态语言本身的特性是个主要原因,把一个稍微复杂点的事物抽像出来用.net或者java来描述,可能要把一个基类派生好几层才能把事说的清楚。动态语言就灵活方便的多,附带的也省掉不少内存开销。

请三思。Python支持多继承,并且多继承也经常是Python中mix-in的做法(虽然有人反对这种用法)。这使得Python需要支持MRO(Method Resolution Order,方法解析顺序),除了类型上的方法表之外,还需要维护一个链表。Java和C#这样的单继承静态类型语言则没这个麻烦,方法解析直接通过每个类型上的方法表就OK。
事实上越动态需要维护的数据就越多。这不是“省掉内存开销”的理由。

tomqyp 写道
从我这段时间的使用经验,以及一些language shootout来看python比java和.net的内存占用小不少,这又是为什么呢?

不吧。
Language shootout这种东西信者有不信者无。我是倾向于不以它为参考标准的。
JVM和CLR都可以在极小的内存占用量的模式下运行。像Sun SPOT,总共才几MB内存(要多的可以自己加……),JVM也照样能跑;.NET Micro Framework中的虚拟机叫TinyCLR,可以在最小64KB RAM、256KB Flash的内存配置下工作。相信这不比桌面上的Python多用多少空间吧?要注意到,嵌入式平台上常见的ARM系处理器使用的是RISC风格的指令集,其代码密度比CISC风格指令集低,所以同样的程序在ARM上编译出来的代码多半比在x86上大,在ARM上代码部分会吃掉比在x86上更多的内存,所以不要以为同样的程序放在嵌入式设备上会自然变小。

为什么桌面/服务器上的JVM和CLR吃内存多?因为有那么多的硬件资源,不用也是浪费。在有比较多内存的条件下,JVM和CLR可以做更多优化(空间换时间),GC的效率也高些。
举例来说,桌面上的CLR是从来不会抛弃JIT编译得到的代码的;生成的代码放在代码堆上;在嵌入式设备中使用的.NET Compact Framework则会在内存剩余量低的时候抛弃掉一些JIT过的代码,也就是说下次再执行那些方法时需要重新JIT。
然后像Sun的phoneME Advance(所谓的CDC profile)里的JVM,叫做CVM。它会选择把程序的元数据(例如类型的名字、成员结构,等等)放在malloc堆上,而桌面上的Sun HotSpot则会把那些数据放在Java堆上由GC管理。这也是因为资源状况不同而做出的不同设计。

所以并不是不能变小,是为了发挥更高的性能而占用了更多资源,仅此而已。Sun的phoneME Feature(所谓的CLDC)在资源真的非常受限是就不JIT编译了,纯解释执行,也能省点内存。

使用引用计数的Python其实不一定就有多省内存。例如Python的int类型,它也是对象,也是在堆上分配空间而不是在栈上。在当前的CPython实现中,计数器要占一个整数,int本身的有效数据也是一个整数,还有些别的元数据来指向类型信息等;它们被作为一个整体在堆上分配空间。如果说元数据和实际的有效数据都省不了,那么这里计数器就占了个冤大头。如果一个Python程序大量使用了int,按比例算实际上浪费在计数器上的空间也不少。就整体“流量”来看,有足够内存空间的时候,引用跟踪式的GC比引用计数式要高效,因为前者分配空间和释放都是大块进行的,后者则必须不断维护中间状态。笼统说,引用计数需要更多操作,只是它们被分散在程序运行的整个过程中,基本不会引起长时间的暂停而已。

mathgl 写道
python的gc是 最简单的 reference counting..是耗不了什么资源。。

调用c lib也简单。比java好多了。。jni还得留神一不小心弄个crash就头大了。

而且CPython的内存管理不是单纯的引用计数。为了解决循环引用的对象的释放问题,CPython实际上还有一个标记-清除式的GC作为备份,偶尔会出来清理一下。
而正是因为引用计数,如果要对CPython写C扩展的话,C代码中使用的Python对象的引用都必须格外小心,要维护好它的计数状态,不然“一不小心弄个crash就头大了”。

如果是简单的标记-清除式GC,它完全可以在平时不保存任何额外的计数之类的信息,只在GC进行时才分配标记栈(mark stack)等临时数据结构,做完GC又可以马上释放这些临时空间;标记本身可以借用对象中的元数据的一点空间(分配空间时如果有对齐要求的话,对象起始地址的最后一两位就总会是0,所以可以借用),也不会占用额外空间。

总之具体问题要具体分析……
codekitten 2009-08-26
楼上的好牛啊,学到了不少东西。。。。
Global site tag (gtag.js) - Google Analytics