Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interpreted languages with manual memory management?

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?


1 Answers

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.

Isn't the major concern about interpreted languages the non-deterministic delays (or space complexity when there isn't enough delay) of garbage collection?

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 and delete. Any language with new and delete has pointers: by definition, whatever new 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".

like image 192
Norman Ramsey Avatar answered Sep 27 '22 17:09

Norman Ramsey