4 ms·
So the memory in Erlang is isolated per thread basis, and it makes Erlang more scalable. While in Java we have only common/shared memory.
by Egregore 16y ago
So the memory in Erlang is isolated per thread basis, and it makes Erlang more scalable. While in Java we have only common/shared memory.
- mryall 16y ago> While in Java we have only common/shared memory. That isn't entirely true. There are ThreadLocal variables in Java. However, these have some performance ramifications and have to be carefully managed so they don't leak, basically because the system wasn't designed with this kind of storage in mind.
- angusgr 16y agoFrom my memories of Java ThreadLocals, these are still common/shared memory. The ThreadLocal property is a reference - a convenient way to scope access without locking - but the objects stored are still in shared memory. For example, correct me if I'm wrong, but in Java if you do something like: MyAwesomeClass myObject = new MyAwesomeClass(); myThreadLocal.set(myObject); myOtherObject.someField = myObject; Then the thread local and the field value are references to the same object, in the global heap. Any thread can get to "myOtherObject.someField" and change my thread's local copy. This specific example is probably bad design, but the underlying difference is between a shared memory design and a message passing share-nothing design, where the latter doesn't let you make that kind of mistake. In Erlang the paradigm is different enough that my bad example doesn't really translate[1], but even if two similar references were made equivalent, they're to _immutable_ objects not references - so from the programmer's point of view they're never shared at all. In addition, if you want to share something then you send a message so the other process (aka thread) always has their own distinct copy. [1] The process dictionary is kind of the same as thread local storage, but the kind of state you'd assign via a reference on a mutable field is dealt with differently.
- ww520 16y agoThat is an explicit sharing of an object between the thread-local-storage and the global heap by the programmer. If MyAwesomeClass is readonly in all methods or it is copied when assigned to myOtherObject, then it's the same as Erlang.
- mryall 16y agoThat's an interesting point. If the Erlang language can stop the programmer making mistakes like unintentional reference publishing across threads, that sounds fantastic.
- angusgr 16y agoThat's one of its major intentions. There's a fairly good summary here: http://ulf.wiger.net/weblog/2008/02/06/what-is-erlang-style-concurrency/ http://ulf.wiger.net/weblog/2008/02/06/what-is-erlang-style-...
- rubyrescue 16y agoalso Erlang "threads" are called processes but are not OS threads nor processes - there is generally one scheduler per core and the processes are swapped in and out by the scheduler.
- silentbicycle 16y agoThey're more like coroutines, but they can be safely pre-empted because Erlang has very little mutable data. Erlang's scheduler also takes dataflow (e.g. which processes have new messages to process?) into account, so some kinds of overhead are O(active processes) rather than O(processes).
- hassy 16y agoThe GC in Erlang VM is also per-process which allows it to be soft real-time. An application can be using gigabytes of memory, but it it's split between thousands of processes, garbage collection can be very very fast because the GC only needs to work through a small heap at a time.
- mononcqc 16y agoAnd to my understanding it can be done on processes not currently scheduled so there is very little visible impact.
- silentbicycle 16y agoYou can also measure the amount of memory a process tends to use in typical operation, then spawn it with an appropriately sized heap. It never needs to do GC at all, it just dies and frees its heap when complete. Look at min_heap_size in spawn_opt/* . It's the same concept as giving a copying garbage collector really large subspaces - GC only happens when one fills. Giving each process its own heap means that the GC pauses will still be brief.
- jbooth 16y agoIt's generally suggested that you make heavy usage of the private and final keywords when writing Java code in general and concurrent java code in particular. ExecutorService + SynchronousQueue/LinkedBlockingQueue + Callables without mutable state = basically a functional coroutine model of programming in Java with non-lispy syntax. If you're doing it right, you're not allocating new threads for every task (and neither is Erlang, they're "cheating" in roughly the same way I'm describing - their "threads" are really "tasks"). You push tasks onto your work queue, taking up very little memory per task, and your ExecutorService takes care of them. The only difference is you have to set up your ExecutorService yourself, which is a plus and a minus compared to the runtime implicitly managing one for you.. sometimes it'd be convenient to have a default coroutine manager, I guess.