具有手动内存管理的解释语言?
哪些解释型语言无指针语言(IE:Python、Java、Perl、PHP、Ruby、Javascript 等)具有手动内存管理功能?我不记得曾经听说过。
解释型语言主要担心的不是垃圾收集的非确定性延迟(或没有足够延迟时的空间复杂性)吗?那么为什么不直接写一些与 Java 完全一样的东西,而是强制你手动释放内存呢?
编辑
我所说的手动内存管理是指该语言将引用对象,并且您可以使用引用删除对象。
示例:
Object a = new Object(); // a is a reference to the object
Object b = a; // b is a reference to the same object
a.method(); // fine
delete b; // delete the object referenced by b
a.method(); // null dereference exception
那么在像这个示例这样的语言中可能存在哪些警告(除了内存泄漏)?
Which interpreted languages pointer-free languages (IE: Python, Java, Perl, PHP, Ruby, Javascript, etc) have manual memory management? I don't recall ever hearing of one.
Isn't the major concern about interpreted languages the non-deterministic delays (or space complexity when there isn't enough delay) of garbage collection? So why not just write something exactly like Java, but forces you free memory manually?
EDIT
What I mean by manual memory management is that the language would have references to objects, and you can delete the object using a reference.
Example:
Object a = new Object(); // a is a reference to the object
Object b = a; // b is a reference to the same object
a.method(); // fine
delete b; // delete the object referenced by b
a.method(); // null dereference exception
So what caveats (Other than memory leaks) could there be in a language like this example?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
这个问题背后的前提有点狡猾:
内存模型是语言的属性,而不是其实现。
被解释是实现的属性,而不是语言。
示例:
编程语言Scheme具有自动内存管理功能,并且有数十种解释实现,而且还有一些优秀的本机代码编译器,包括Larceny、Gambit和PLTScheme(其中包括两者一个解释器和一个 JIT 编译器进行无缝转换)。
编程语言Haskell具有自动内存管理功能;两个最著名的实现是解释器 HUGS 和编译器 GHC。还有其他几个值得尊敬的实现,它们在编译为本机代码 (yhc) 和解释 (Helium) 之间平均分配。
编程语言 C 具有手动内存管理功能,虽然世界上到处都是 C 编译器,但我们这些年纪大到还记得辉煌的 20 世纪 80 年代的人可能还记得 Saber-C 或 C-terp,这两个对于 MS 非常有用的 C 解释器- DOS。
尽管如此,您的问题背后有一个真实的观察:通常会编译具有手动内存管理的语言。为什么?
手动内存管理是一项遗留功能,通常用于与遗留代码兼容。遗留语言通常已经足够成熟,可以拥有本机代码编译器。
许多新语言都是由实现定义的。构建解释器比构建编译器更容易。在解释器中实现简单的自动内存管理比在本机代码编译器中实现高性能自动内存管理更容易。因此,如果语言从其第一个实现中获取其定义,则自动内存管理与解释相关,因为在解释设置中,实现更容易。
手动内存管理也(有时甚至是合理的)用于提高性能。 Ben Zorn 在 20 世纪 90 年代的出色实验研究表明,自动内存管理与手动内存管理一样快或更快,但需要大约两倍的内存。因此,手动内存管理通常用于内存稀缺的非常小的设备,以及内存加倍昂贵的非常大的数据中心。 (有时也被不太了解内存管理但听说垃圾收集很慢的人使用。他们在 1980 年是对的。)当担心性能时,您通常会发现本机代码编译器而不是比口译员更重要。
一些真正有趣的例外也来自这个原则。例如,FORTH 和第一个 PostScript 实现都被设计为在小型嵌入式设备(望远镜和打印机)上运行,这些设备内存资源稀缺,但计算时间不是一个因素。这两种语言最初都是使用比本机代码更紧凑的字节码实现的,并且都具有手动内存管理功能。所以:具有手动内存管理的解释器。 (PostScript 的更高版本添加了垃圾收集选项。)
总而言之:
自动内存管理与手动内存管理是语言。
编译与解释是实现。
原则上这两个选择可以并且是正交的,但出于实用的工程原因自动内存管理经常与解释相关。
我不知道人们对编程语言的解释实现有一个主要关注点。按字母顺序排列,Lua、Perl、PostScript、Python 和 Ruby 都非常成功,而 Icon、Scheme 和 Squeak Smalltalk 则比较成功。不可预测的延迟引起关注的唯一领域是硬实时计算,例如控制汽车刹车的 ABS 系统(如果您驾驶的是一辆足够豪华的汽车)。
编辑问题后添加的注释:您将“解释”更改为“无指针”。但是您在评论中说您的意思是询问带有
new
和delete
的语言。任何带有new
和delete
的语言都有指针:根据定义,无论new
返回的是一个指针。 (在某些语言中,也可能有其他指针来源。)所以我认为你的意思是“没有指针算术和没有地址运算符的语言”。The premises behind the question are a bit dodgy:
The memory model is a property of the language, not its implementation.
Being interpreted is a property of an implementation, not a language.
Examples:
The programming language Scheme has automatic memory management, and it has many dozens of interpreted implementations, but also some fine native-code compilers including Larceny, Gambit, and PLT Scheme (which includes both an interpreter and a JIT compiler making seamless transitions).
The programming language Haskell has automatic memory managemend; the two most famous implementations are the interpreter HUGS and the compiler GHC. There are several other honorable implementations split about evenly between compiling to native code (yhc) and interpretation (Helium).
The programming language C has manual memory management, and while the world is full of C compilers, those of us old enough to remember the glorious 1980s may remember Saber-C or C-terp, two very useful C interpreters for MS-DOS.
Nevertheless there is a truthful observation behind your question: languages with manual memory management are typically compiled. Why?
Manual memory management is a legacy feature, often used to be compatible with legacy code. Legacy languages are typically mature enough to have native-code compilers.
Many new languages are defined by an implementation. It is easier to build an interpreter than to build a compiler. It is easier to implement simple automatic memory management in an interpreter than to implement high-performance automatic memory-management in a native-code compiler. So if the language gets its definition from its first implementation, automatic memory management correlates with interpretation because in the interpreted setting, the implementation is easier.
Manual memory management is also (and sometimes even justifiably) used to improve performance. Ben Zorn's excellent experimental studies from the 1990s show that automatic memory management is as fast or faster than manual memory management, but requires about twice as much memory. So manual memory management is often used on very small devices, where memory is scarce, and in very large data centers, where doubling memory is expensive. (It's also sometimes used by people who don't know much about memory management, but who have heard that garbage collection is slow. They were right in 1980.) And when there's a concern for performance you usually find a native-code compiler rather than an interpreter.
Some of the really interesting exceptions also come from this principle. For example, both FORTH and the very first PostScript implementations were designed to run on small embedded devices (telescopes and printers) where memory resources were scarce but compute time was not a factor. Both languages were first implemented using bytecodes that were more compact than native code, and both featured manual memory management. So: interpreters with manual memory management. (Later versions of PostScript added an option for garbage collection.)
In summary:
Automatic versus manual memory management is the language.
Compiled vs interpreted is the implementation.
In principle the two choices can be and are made orthogonally, but for pragmatic engineering reasons automatic memory management frequently correlates with interpretation.
I wasn't aware that there was a major concern about interpreted implementations of programming languages. In alphabetical order, Lua, Perl, PostScript, Python, and Ruby are all wildly successful, and Icon, Scheme, and Squeak Smalltalk are moderately successful. The only area in which unpredictable delays cause concern is in hard real-time computing, like the ABS system that controls the brakes of your car (if you drive a sufficiently fancy car).
Note added after question was edited: You changed "interpreted" to "pointer-free". But you say in a comment that you mean to ask about languages with
new
anddelete
. Any language withnew
anddelete
has pointers: by definition, whatevernew
returns is a pointer. (In some languages, there may be other sources of pointers as well.) So I think what you mean to say is "languages without pointer arithmetic and without an address-of operator".Forth 具有可以通过 FORGET 释放的堆栈内存区域。
Forth has stacked regions of memory that can be released with FORGET.
不存在解释性语言这样的东西。语言既不是编译的,也不是解释的。语言只是是。语言是一堆抽象的数学规则。解释或编译是语言实现的特征,它们与语言无关。 每种语言都可以由编译器或解释器实现;大多数现代高性能语言实现实际上都使用两者,并根据特定上下文中哪一个更快而在它们之间进行切换。
C是编译语言吗?那里有 C 解释器。 Python 是解释性语言吗?当前所有 8 个 Python 实现都使用编译器。
因此,由于每种语言都可以有解释性实现,因此 C 和 C++ 是具有手动内存管理功能的解释性语言的示例。 (这不仅仅是一场理论上的吹毛求疵的竞赛,实际上有 C 和 C++ 解释器。VxWorks 实时操作系统甚至在内核中包含一个权利,NASA 曾经使用过这个解释器来修复航天器上有缺陷的内核模块。)
另一个例子是 1958 年的 Lisp 的第一个版本:它具有手动内存管理(基于引用计数),但仅几个月后就被一个版本取代从那时起,它就一直使用自动内存管理。尽管如此,任何语言都可以用编译器或解释器来实现,所以我不知道该版本是否有解释实现或编译实现。 (事实上,我不确定它是否被实现了。)
如果你稍微放松你的标准并意识到内存管理只是一般资源管理的一个特例,那么你就会发现几乎所有语言,无论您想将它们称为编译型还是解释型还是其他完全不同的语言,都至少对某种类型的资源具有某种形式的手动资源管理(文件句柄、数据库连接、网络连接、缓存……)。
There is no such thing as an interpreted language. A language is neither compiled nor interpreted. A language just is. A language is a bunch of abstract mathematical rules. Interpretation or Compilation are traits of a language implementation, they have nothing to do with the language. Every language can be implemented by either a compiler or an interpreter; most modern high-performance language implementations actually use both and switch between them depending on which one is faster in a particular context.
Is C a compiled language? There are C interpreters out there. Is Python an interpreted language? All 8 current Python implementations use a compiler.
So, since every language can have an interpreted implementation, C and C++ are examples of interpreted languages with manual memory management. (And this is not just a theoretical hair-splitting contest, there are actually C and C++ interpreters out there. The VxWorks real-time operating system even contains one right in the kernel, and NASA once used this interpreter to fix a buggy kernel module on a spacecraft.)
Another example would be the very first version of Lisp from 1958: it had manual memory management (based on reference counting), but it was replaced only a couple of months later with a version with automatic memory management, which it has used ever since. Although again, any language can be implemented with either a compiler or an interpreter, so I don't know whether that version had an interpreted implementation or a compiled one. (In fact, I'm not sure whether it was implemented at all.)
If you relax your criteria a little bit and realize that memory management is only a special case of general resource management, then you will find that pretty much all languages, whether you want to call them compiled or interpreted or something else entirely, have some form of manual resource management for at least some kind of resource (file handles, database connections, network connections, caches, ...).
在一些高性能解释语言中,例如 Lua,您可以手动处理垃圾收集。请参阅lua_gc。
In some high performance interpreted languages like Lua, you can manually handle garbage collection. See lua_gc.
有一些可用的 C/C++ 解释器,例如这个。
我自己没有尝试过,但我认为既然它声称兼容编译的C/C++,它就需要有“手动”内存管理。
There are some C/C++ interpreters available, for example, this one.
Did not try it out by myself, but I think since it claims to be compatible to compiled C/C++, it needs to have "manual" memory management.
原因是循环引用、空指针异常和多重引用。一个简单的例子:
如果在上面的例子中,
b
现在为空,那么在重新定义变量时就会遇到一些主要问题。例如,不将a
设置为 null,而是将其设置为c
会怎样?b
也会是c
吗?您可以在维基百科上阅读有关其他问题的信息,例如循环引用。
The reason is circular references, null pointer exceptions and multiple references. A simple example:
If, in the example above,
b
is now null, you end up with some major problems when redefining variables. For example, instead of settinga
to null, what if you set it toc
? wouldb
also bec
?You can read about other problems, like circular references, on wikipedia.
所以回答这部分问题:
对于某些系统来说,这可能是一个问题。对于其他系统来说并不是什么问题。运行垃圾收集的软件可以比仅调用 malloc 的系统更快地分配内存。当然,您最终会在 GC 时间之后支付时间。
以基于网络的系统为例。您可以在处理请求期间分配所有内存,然后 GC 可以收集内存。最终结果可能不会那么好,但你明白了。
垃圾收集有很多不同的策略。哪种策略最适合系统取决于需求。但即使您需要绝对确定性,您也可以使用类似以下内容的内容: Realtime Java
So answering this part of the question:
This might be a concern for some systems. Not so much a problem for other systems. Software running with garbage collection can allocate memory faster than systems that just call malloc. Of course you end up paying the time later at GC time.
Take a web-based system for example. You can allocate all the memory during the handling of a request, and the GC can collect afterwards. It might not end up working out quite like that, but you get the idea.
There are a lot of different strategies for garbage collection. Which strategy is best for the system will depend on the requirements. But even if you require absolute determinism, you can use something like: Realtime Java
解释并不一定意味着收集垃圾。 Perl、Tcl、Python 等等。我相信它们都使用简单的引用计数,因此内存回收是确定性的,尽管一点也不透明(曾经在 Perl 程序上尝试过
strace
吗?)。Interpreted does not necessarily imply garbage collected. Perl, Tcl, Python, etc. etc. I believe all use simple reference counting, so the memory reclamation is deterministic, though not at all transparent (ever tried
strace
on a Perl program?).Python 的 API 官方允许打开或关闭延迟垃圾收集 -
检查标准库的“gc”模块的文档:
http://docs.python。 org/library/gc.html
但这并不是它与静态语言相比变慢的原因 - 数据本身的动态特性才是速度差异的主要原因。
Python's API oficially allows one to turn on or off delayed garbage collection -
Check the documentation on the "gc" module of the standard library:
http://docs.python.org/library/gc.html
But that is not what makes it slow when compared with static languages - the dynamic nature of data itself is the mains responsible for the speed differences.
那么 λ haskell 还具有显式内存管理的能力:
正如我们在 λ haskell 中可以清楚地看到的,您也可以进行手动内存管理!XD
进一步信息请参阅:hakell
Well λ haskell has also the ability for explicit memory management:
As we can clearly see in λ haskell you can do manual memory management, too! XD
further info see: hakell