
Do Not Use Go for 32bit Development - abtinf
http://www.abtinforouzandeh.com/2012/04/08/Do-Not-Use-Go-For-32bit-Development.html
======
jesstaa
The strategy the allocator uses is to reserve a large contiguous block of
address space(not memory) on start up and then allocate actual memory from
that block. On 32bit this is around 512MB, on 64bit it's something like 16TB.
This makes allocating and garbage collection far simpler and it really
shouldn't be a big ask for an operating system to give a process a contiguous
block of address space and not interfere with it. But just like the pinning
issue the smaller address space on 32bit means that things that expect to be
at a certain address have a higher likelihood of getting in the way of the
contiguous block.

The fix for both this issue and the pinning issue is big changes to the
garbage collector. Since the language and standard library have stabilised
with Go1, changes to the runtime are going to be the focus of development so
this issue will probably get a fix.

~~~
xpaulbettsx
This is highly dependent on the video card and other PCI devices you are
using, as they will often reserve huge chunks of VA space to map to device
memory (and furthermore, require it to be in low addresses i.e. user space),
making a contiguous reservation difficult.

If you want to see exactly what's happening, SysInternals VMMap
([http://technet.microsoft.com/en-
us/sysinternals/dd535533?ppu...](http://technet.microsoft.com/en-
us/sysinternals/dd535533?ppud=4)) will tell you exactly the VA space layout.

Note that Linux has exactly the same problems with VA space, except they
_default_ to 3/1, instead of NT's default (but configurable) of 2/2.

It seems that a quick fix to this issue would be to lower that number from
512MB to something like 128MB, though I know nothing about Go's internals.

~~~
JoshTriplett
Getting 512MB of contiguous virtual address space does not require 512MB of
contiguous free physical memory; contiguous virtual addresses can map to
discontiguous physical memory.

~~~
astrodust
That's what I thought. The address your user-space program uses and the actual
address in memory are two different things, aren't they?

Isn't this what enables the operating system to scramble the allocations it
gives you to make it harder to implement a buffer-overflow attack?

~~~
JoshTriplett
> That's what I thought. The address your user-space program uses and the
> actual address in memory are two different things, aren't they?

Right. Userspace uses virtual addresses, which get mapped through page tables
to become physical addresses. Some kernel addresses get identity-mapped
(meaning that the virtual address matches the physical address), while some
kernel addresses go through translation as well. (Specifically, on Linux,
kmalloc allocates identity-mapped addresses, while vmalloc allocates virtual
addresses; vmalloc allows you to have a large virtually contiguous buffer
without requiring a large physically contiguous region of free memory.)

> Isn't this what enables the operating system to scramble the allocations it
> gives you to make it harder to implement a buffer-overflow attack?

You can do Address Space Layout Randomization (ASLR) for either virtual or
physical address spaces; you want to do it for whatever type of address an
attacker could otherwise make use of. Userspace processes can use ASLR for
their virtual address space, so that attackers can't make use of fixed
addresses. The Linux kernel doesn't normally map virtual pages to any
particular well-known location in physical address space, either. The kernel
can also use ASLR for some (though not all) of its own kernel-space addresses.
Beyond that, recent versions of Linux also try to avoid exposing kernel-space
addresses to non-root users.

Also note that ASLR doesn't generally introduce enough randomness in a 32-bit
address space.

------
nikcub
> On 32bit Windows machines, processes only have access to 2GB user space
> memory.

You can change this in boot options to 3 or 4 (optimized) or enable PAE. see:

<http://msdn.microsoft.com/en-us/library/aa366778.aspx>

i'd try that before rewriting your code (also kill services you don't need,
which is usually a lot of them. run -> msconfig).

Edit: you also don't mention probably the most important piece of info: which
version of windows you are running.

Edit 2: make sure go is being treated as a background process

Edit 3: it seems a lot of these tips should be in the Go docs for win32 - i'll
add it when I have a moment

~~~
trimbo
Importantly, you will need to recompile with /LARGEADDRESSAWARE.

~~~
4ad
Yeah, that kernel flag is useless without stamping the binaries, and the Go
linker doesn't know about this.

~~~
barrkel
It's just a flag in the PE headers. It can be modified after the fact with a
tool; the Go linker doesn't need to know.

~~~
doug363
But the reason why there is an explicit flag in the first place is that
there's a lot of code out there that doesn't work with pointers >= 0x80000000,
or when pointers could differ by more than that. Things like pointer
"tagging", and signed integer overflow bugs, are examples of the sort of code
that can be affected. Without knowing details about the Go code generation and
runtime/garbage collection, it would be a bit risky to just set the flag and
hope for the best.

~~~
barrkel
Oh, I know; I've written bounds-checking logic for RTLs that use casts to
integers and tests for negativity to check for overrun, implicitly assuming
31-bit address space. My only point is that a limitation of the Go linker does
not preclude setting the flag.

------
algolicious
_At runtime init, Go programs attempt to reserve 512mb of RAM. If they can’t
do this, they crash. Go needs the space because it is garbage collected -
presumably, all GC languages, or any program that takes a similar approach to
memory management, will be susceptible to the same problem._

While it is true that most garbage collected environments will reserve some
memory at startup, a hard minimum of 512 MB is not the norm. Do note that
embedded Java has run on cell phones with minimal amounts of RAM for many
years.

~~~
_delirium
Fwiw, Go doesn't need a hard minimum of 512 MB physical memory, but it does
seem to assume a contiguous 512 MB of virtual address space will be available.
Since every process has 2 GB of virtual address space and grabbing the 512-MB
chunk is the first thing Go does, this should almost always be safe, but on
Windows it appears that can fail to be the case because in some
configurations, DLLs are loaded during initialization and fragment the virtual
address space. I can run Go fine on a 32-bit (Linux) VPS with 256 MB of RAM,
though.

~~~
ismarc
They only get scattered throughout when using cgo with the DLLs loaded by the
Windows system by the application loader rather than by the go runtime. It
appears to be very specific to how Windows loads DLLs at runtime.

~~~
4ad
Yes, though in this particular case the author told me cgo wasn't involved.
This makes it very very peculiar. Usually when I see system DLLs (not 3rd
party) rebasing it's either mallware in other processes that lazily loaded
ntdll.dll and that had to be rebased or some legit program or mallware that
does user mode hooking by injecting DLLs.

It is _NOT_ a Go problem, but Go could implement a workaround making the
address space reservation in teh PE header.

~~~
burgerbrain
Isn't Go normally statically linked if cgo isn't being used? Would that mean
that the DLL's in the virtual address space definitely shouldn't be there?

~~~
4ad
Statically linked in Linux, in Windows the Go runtime and packages are
statically linked into the binary, but the binary itself is dynamically linked
to kernel32.dll because issuing syscalls directly is not supported.

Why was kernel32.dll rebased when Go doesn't force the rebase is a very good
question indeed. I suspect a 3rd party user mode hook, it doesn't even have to
be malware, there are legit "security" and monitoring applications that use
this technique.

~~~
mbe
ASLR I would guess.

~~~
4ad
ASLR support needs to be stamped in the PE header. You can enable it globally,
but the randomization space is smaller than it should matter for this.

It's definitely something to investigate though.

------
ismarc
Looking through the linked bug and the testing they did, the issue doesn't
appear to be using Go for 32 bit systems. It's using 32 bit compiled Go
programs that use cgo on 64 bit Windows systems.

Understanding the why of the issue is extremely important in this case. Based
on the discussion in the bug report, I would expect that using the 32 bit
compiler for 32 bit architectures and 64 bit for 64 bit architectures would
not result in the issue occurring. Before abandoning Go, I would very much
identify that this is indeed the case. With Go's young age, I would very much
use the architecture specific compilers for the specific targets which is
different than normal expectations, but not at all unreasonable.

~~~
abtinf
Unfortunately, this is not the case. 32bit compiled runs great on 64bit
machines, where it gets the full 4gb of space and memory fragmentation at init
is very unlikely to be a problem.

Edit: similarly, 64bit also is immune because of how the main platforms
allocate virtual address space to clients.

~~~
ismarc
Hrm, that actually makes the issue tricky to solve. I don't have any Windows
machines to work with, so I can't test, and I'm not very familiar with using
Go on Windows in general, but is it possible to specify delayed load of the
DLLs? That should allow the main Go system to get fully initialized (and
allocate the chunk of memory it needs) before loading the DLLs needed for the
cgo portions.

~~~
4ad
Nobody is using cgo, it's the system DLLs which get loaded in the middle of
the address space. This is very very unusual, Windows tries hard to avoid such
things.

It could be solved by making the initial virtual address space reservation in
the PE header, not requesting it in the initialization path, that would always
work, even with cgo.

------
dhconnelly
I'm a big fan of Go, but it would be nice to see a caveat about 32 bit systems
on the Go website or blog. Or at least some official warning or notice that
isn't just a mailing list discussion.

------
malkia
If 512mb are needed as contiguous space, then one hacky solution is do define
a BSS section of 512mb, or in "C" terms - global array -

char mem[512 * 1024 * 1024];

the executable loader would "allocate" this memory before loading any dlls,
and later dlls that were supposed to be in that memory would be rebased

Oh, and somehow Go would need to use this memory rather than allocate it.

~~~
barrkel
This would, however, allocate memory rather than just address space.

(Yes, it may be lazily committed, but it's still not as cheap as address
space.)

~~~
malkia
Once this is done, you can VirtualFree it (starting/ending from page
boundaries), and let it back to the OS. Yes for some short amount of time,
while it loads and goes to your code the memory is reserved.

------
ExpiredLink
> I’m sitting here rewriting a ton of Go code in C.

I don't believe a single word. He pretends to have written "a ton of Go code"
without discovering the "real show stopper"? I'm not a Go fan (quite the
contrary, Go isn't the step forward from C++ and Java I expected from Google).
But this Anti-Go campaign few days after 1.0 smells.

~~~
eternalban
> Go isn't the step forward from C++ and Java I expected from Google

Go is a lovely language, imo. Quirky in parts, but definitely a charmer, very
fun to code in, and once you get the Go zen, simple and elegant code
effortlessly follows. I haven't had this much fun since Java came out in mid
90s.

Of course, I do agree with the other comments that would like to see
Golang.org be more clear as to the platform coverage and the current state of
Scheduler and MM -- but they are certainly upfront in the source tree (c.f.
proc.c header comment), forums, and the issue tracker.

So hacker fine print is there and available, and frankly (IMHO) that approach
to disclosure may turn out to be a good filter for the growth of Go community.

The issue at hand is nothing that time and resources will not solve -- they
just ran out of time (c.f. RSC's comment before Abtin's in the issue.)

~~~
pjmlp
>> Go isn't the step forward from C++ and Java I expected from Google

>

>Go is a lovely language, imo. Quirky in parts, but definitely a charmer, very
fun to code in, and once you get the Go zen, simple and elegant code
effortlessly follows. I haven't had this much fun since Java came out in mid
90s.

Go is a step backwards in language abstractions, throwing away many of the
abstractions that have become mainstream in the last decades.

~~~
luriel
Sometimes to move forward you have to take a step back.

Just because some abstractions have become mainstream doesn't mean they are
good.

I think precisely what many people love about Go is that it throws away lots
of unnecessary abstractions and complexity that people have come to expect
from languages this days.

Go's approach is a breath of fresh air.

------
caf
This same Go implementation design earlier ran into some issues on Linux, too
- in this case, with distributions setting conservative RLIMIT_AS limits.

The technical details are interesting
([https://groups.google.com/forum/#!msg/golang-
dev/EpUlHQXWykg...](https://groups.google.com/forum/#!msg/golang-
dev/EpUlHQXWykg/LN2o9fV6R3wJ)) and Linus' response
([http://lkml.indiana.edu/hypermail/linux/kernel/1102.1/00233....](http://lkml.indiana.edu/hypermail/linux/kernel/1102.1/00233.html))
is also instructive.

~~~
aidenn0
I had a similar issue with the default configuration of SBCL on a 64-bit
vhost; the 64-bit version asks for 8gb of VAS and the vhost had a fairly small
limit on VSIZE. Fortunately the heap allocation is configurable in SBCL;
perhaps doing something like that on go would be the right thing?

------
cjensen
In my opinion, the problem is that 32-bit Windows is intentionally broken by
Microsoft.

Unlike other 32-bit x86 operating systems, the consumer version of Windows
refuses to addresses more than the first 4GB of physical memory, and on most
machines a quarter to half of that space is consumed by PCI address space.

Yes there are hacks around this. But the right way to deal with this is to
just fold and accept what Microsoft is imposing: use a 64-bit version of
Windows whenever possible and enjoy your memory.

Once on a 64-bit OS, you can either write a 64-bit program, or you can write a
32-bit program and use a compiler option to get the full 32-bit address space.
(Microsoft's compilers assume by default that you are an idiot who uses signed
values for addresses and your program will break if they give you more than
2GB of virtual address space)

The other lesson is don't use experimental languages you are uncertain of for
actual product.

~~~
pjmlp
The same also applies to other 32 bit OS, this is not Windows specific.

~~~
tankenmate
Umm no, other OSes have different defaults for mapping and have different
heuristics for how and where they map devices and libraries. Go on 32bit Linux
rarely has the problems that the Windows versions do.

~~~
4ad
The PCI mappings are the same, either in Linux or Windows. I do agree that
this particular report is a Windows problem, 512MB contiguous address space
should be available at program initialization in every case.

I do agree that Go on 32 bit Linux rarely has any problems, but this is true
for Windows as well. What happened in the last few days is blown out of
proportion.

~~~
tankenmate
The _size_ of the mappings are probably the same, but there are very few PCI
devices that _require_ to be mapped to a particular address, as opposed to a
certain area of memory, i.e. under 4G or 1M.

~~~
4ad
Nothing is mapped under 1M in protected mode with paging enabled, that's user
space. They still have to be mapped under 4G because 4G is all you got on 32
bit.

------
fleitz
Somewhere in the source of Go will be the number 536870912, change this number
to 134217728. Problem should largely be solved.

Note: I'm not a Go dev, or have even programmed in it, but logically it should
be a quick fix that you can try to save you rewriting your codebase.

Given the importance of the number it's probably a #define or constant so
should be pretty easy to find in one of the header files.

~~~
4ad
It's 512<<20, and a proper way to fix it, on Windows, at least, would be to
reserve the address space in the PE header, not ask the operating system in
the process initialization path.

------
tashmahalic
This is my understanding of the problem: when a Go program is initialized on
32-bit windows or linux systems, it tries to allocate 512MB of contiguous
virtual ram. When the virtual address space is too fragmented, the
initialization will fail and the Go program won't start. Is this correct?

We're considering using Go for an end-user desktop application for Mac,
Windows, and Linux. Of course, we don't have control over whether our users
have a 32-bit or 64-bit system. And, of course, our app has to work 100% of
the time. What can we do to make Go work 100% of the time on these 32-bit
systems?

~~~
JoeAltmaier
Don't know what it means for the virtual address space to be fragmented. Each
process begins with a pristine virtual address space.

~~~
4ad
Mostly, but not really, apart from the binary image itself, its dependent
shared libraries are also loaded, and the various images loaded might have
virtual address space reservations marked in the header. In normal scenarios
there should be enough contiguous address space, Go programs only link to
ntdll.dll and winmm.dll. While it's true that on recent Windows versions these
two shared objects pull around 30 other shared objects, all the DLLs shipped
with Windows have a base address chosen so that they only take a very small
chunk of address space and most address space is contiguous. 512MB of
contiguous reservation shouldn't be a problem to get.

The fact that this is not happening means that 3rd party DLLs are loaded, this
happens if you use a program, knowingly or not, that install user mode hooks.

------
JoeAltmaier
x86 32-bit is actually capable of addressing any amount of memory, using the
right compilation model. Flat 32-bit has a 4GB limit sure. But segemented, it
can access any amount of virtual memory, with the caveat of only 4GB per
allocation.

Probably no OS supports this any more. But the instructions set and memory
management units support it, or used to in early Pentium days.

~~~
caf
Segment:Offset addresses are converted to 32 bit linear addresses; the segment
base address in the segment descriptor is a 32 bit value.

~~~
JoeAltmaier
On a 64-bit architecture its 64-bit. 32-bit programs run there.

Also, as noted elsewhere, on 32-bit architectures there's segment swapping
too. In fact I wrote an OS that segment swapped before the 386 came out, when
the 286 was king. Probably the only one out there; a pretty crazy notion and
the 386 came out a year later with paging.

~~~
caf
Even in 64-bit mode the base address for code and data segments remains 32
bits - it is only expanded to 64 bits for call gate descriptors, IDT gate
descriptors, LDT descriptors and TSS descriptors. The base address for the FS
and GS selectors can be set to a 64 bit value, but the upper 32 bits are
ignored in compatibility mode (ie when a 32 bit task is running).

The point about being able to implement segment-swapping is well-taken
however.

------
kokoloko
I think Go, Mono, Ruby, Python et al should team up to create a reusable
garbage collector library that can compete with the OpenJDK one. For me, it's
the single biggest piece falling behind on non JVM languages. The performance
and "tunnability" are unmatched right now. Bonus points would be for a real
time garbage collector, a la IBM Metronome.

------
tashmahalic
We need to decide if Go is a suitable language to build our app with. Our app
will be deployed on end-user 32-bit systems, and needs to work 100% of the
time.

Is there someone here who can say either: (1) Go will fail sometimes on 32-bit
systems, don't use it until this problem has been fixed, or (2) there are
things you can do to always avoid the 32-bit problems.

?

~~~
tashmahalic
(and if there's no one here with an informed answer, where should i ask this
question? Thanks.)

------
Dylan16807
How many dlls are loaded into the process? Have you looked at all the loaded
dlls at the moment allocation fails to look at the potential for remapping?

Edit: Okay I see a memory map on the bug report. So why not poke at a copy of
kernelbase.dll?

------
pjmlp
This only goes to show that Go is still not production ready.

~~~
jemeshsu
YouTube is using Golang <http://code.google.com/p/vitess/>. So 10% of Internet
traffic now depends on it. I wouldn't call it not production ready.

From the project goal page:

"Go is miles ahead of C++ and Java in terms of expressibility and close in
terms of performance. It is also relatively simple and has a straightforward
interaction with Linux system calls.

The main drawback is also its strength - the garbage collector. vtocc has made
spot optimizations to minimize most of the adverse effects of Go’s stop-the-
world gc. At this point, we are trading some amount of performance for greater
creativity and efficiency at lower layers. unless you’re trying to max out on
qps for your servers, you should see acceptable performance from vtocc. Also,
go’s garbage collector is being improved. So, this should only get better over
time. Go’s existing mark-and-sweep garbage collector is sub-optimal for
systems that use large amounts of static memory (like caches). In the case of
vtocc, this would be the row cache. To alleviate this, we intend to use
memcache for the time being. If the gc ends up addressing this, it should be
fairly trivial to switch to an in-memory row cache. Note that the row cache
functionality is not fully ready yet."

~~~
pjmlp
"Go is miles ahead of C++ and Java in terms of expressibility and close in
terms of performance. It is also relatively simple and has a straightforward
interaction with Linux system calls."

How can this be when Go lacks:

\- enumerations

\- exceptions

\- generics

\- dynamic loading

The short compilation times are possible in any language with modules.

Channels are available as part of concurrency libraries in Java, .NET, C++ and
Erlang.

Goroutines are also possible in other languages, in form of continuations or
task pools.

~~~
sirclueless
None of those things are really roadblocks to Getting Shit Done though, except
maybe dynamic loading.

Go has plenty of support for global constant values that take the place of
enumerations, even to the point of having an "iota" syntax to make
initializing constants easier.

Exceptions are generally an anti-pattern in my opinion: a hack to get around
the ability to return multiple values from a function, so that error
conditions can be handled in-band. The other technical challenge exceptions
sometimes provide -- guaranteed cleanup after code that might fail to execute
-- can be handled by Go's deferred function execution.

Generics are a powerful abstraction, but Go has very good support for
(un)boxed values and interfaces, so the only thing you would get from generics
is a bit more type safety. The additional complexity required to support
generics isn't worth it.

Dynamic loading is arguably a blocker for certain modes of development and
distribution, but by not supporting dynamic loading, Go can make tremendous
simplifications in its module system. Making the assumption that every go
library is distributed in source form greatly reduces compatibility friction
and runtime bugs. "DLL Hell" may be a "solved" problem on most systems
nowadays, but there are a lot of moving parts to enable that.

The simplifications that Go makes are 100% worth it in my opinion. There is
one place where Go sacrifices something that can't be replaced is that a stop-
the-world garbage collector may be unacceptable for some applications. Other
than that, codebases aren't actually served by having too much power in their
languages, even if an individual programmer might be.

~~~
pjmlp
ioata is a poor man's solution to enumerations. Why should I do the work for
the compiler?

Even C has enumerations, a language developed in 1972! This is how modern Go
is.

The lack of generics makes everyone that writes generic data structure code
like it was the 90's again. Copy-pasting code or writing template processors
to generate code. Talk about evolution.

Dynamic loading is an important way to write modular applications that can be
composed on run-time. Something like Eclipse would be impossible to write in
Go, due to performance constrains of interprocess communication.

If Go did not had Google behind it, I doubt it would be noticed, it would fail
as just another language.

Look how successful Limbo and Alef were. And Go is nothing more than a
reinvention of them.

~~~
agentS
People who write data structures just give up type-safety when doing so. They
don't copy-paste code or write template processors, afaik. A Left-leaning Red-
Black Tree, for example:
<http://gopkgdoc.appspot.com/pkg/github.com/petar/GoLLRB/llrb>

Holding up Eclipse as an example citing performance is perhaps not the best
idea. And Chromium seems to do just fine (performance-wise) using IPC between
renderer processes and the main process.

~~~
pjmlp
Go fanboys always cite Chromium as a gold example of process IPC and why
dynamic loading is not required for plugins.

What people fail to see is that Chromium is just one use case.

An IDE for example, would explode memory wise if every single plugin would be
a separate process. Then all plugins that require real time interaction with
source code manipulation would suffer from heavy context switching.

~~~
agentS
Evidence of this memory explosion? Keep in mind that Go processes tend to take
significantly less memory than Java processes, especially when dealing with IO
related code, i.e. sockets
([http://shootout.alioth.debian.org/u64q/benchmark.php?test=al...](http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=go&lang2=java)).

Sure, if you do it stupidly, and have a highlighter process per open document
or something, it could add up over time. But if you share highlighter
processes between documents, you have 1 process that you keep open for the
lifetime of the application. A simple HTTP server in Go takes < 5 MB of RAM in
its steady state, a server using domain sockets would probably be comparable.
And even better, a bug in the highlighter doesn't mean your main application
crashes. If it crashes, the parent merely restarts the process. Even better,
its more secure, in the sense that you can run your highlighter with
absolutely no OS privileges. Also, this allows for plugins written in any
language that supports sockets.

All I'm saying is that there's no evidence that IPC isn't performant enough.
And IPC comes with security, compatibility, and isolation advantages, to boot.

Note that I'm definitely not saying that dynamic loading wouldn't be nice. Do
I miss it, when working with Go? Not for my use cases. "Plugins" for servers
don't really make sense. But dismissing Go because it doesn't target every
use-case at the moment is somewhat shortsighted.

~~~
pjmlp
Well, if I look at my plugins folder I have around 200 jar files.

Many of those do provide more than one plugin, which puts it way above 200
plugins.

The approach one process per plugin won't scale in such cases.

The lack of IPC performance for heavy communication, like it happens with
plugins, is the main reason why microkernel based OS are yet to become
mainstream.

~~~
agentS
Are all of those plugins active all the time? I doubt it.

This discussion is getting a little off track.

I'm simply saying that dismissing Go for not supporting plugins is rather
illogical, as there are a lot of use cases that have no need of plugins.
Servers being a good example of one of these use cases.

------
someCTO
It seems like the actual problem is you chose to use windows...

~~~
eridius
It does seem rather surprising to me that Windows is so broken that a program
can fail to reserve 512MB of virtual address space as the very first thing it
does at launch.

Of course, the 2GB limit on 32bit Windows programs also seems terribly broken
to me.

~~~
Mavrik
You mean the identical limit that also 32-bit Linux applications on x86 have
without reconfiguring kernel for different split?

It seems Windows bashing without any background knowledge is becoming popular
again -_-

~~~
someCTO
Running a PAE kernel on 32 bit is pretty standard at this point, I believe.
Please correct me if I missed something.

~~~
yuhong
It has nothing to do with PAE, but 3G/1G split I think is default on Linux.

~~~
someCTO
That does not address the 512MB of virtual address problem, which is not an
issue with PAE.

~~~
4ad
Yes it is because PAE doesn't change the address space of processes. PAE let's
you use more physical memory, the address space of each process is still the
same, because 2^32 is still 2^32 with PAE.

------
xal
Just compile with the gcc go compiler and you are set. Running 32 bit on
servers is just like running IE6 on desktops. It's time to upgrade. Also every
language that uses a conservative GC behaves this way, it's not just a GO
issue.

~~~
mikeash
What other popular languages use a conservative GC, though?

~~~
sausagefeet
I believe Mono uses Boehm GC, which is conservative:

[http://www.mono-
project.com/Mono:Runtime#Mono.27s_use_of_Boe...](http://www.mono-
project.com/Mono:Runtime#Mono.27s_use_of_Boehm_GC)

~~~
kingkilr
They've introduced S-Gen which is a good, precise, generational collector. I
don't know if it's the default, but it is considered production ready IIRC.

~~~
jstedfast
It'll be the default in Mono 3.0 (or 2.12, whatever we decide to call it).
Currently, in Mono 2.10, Boehm GC is the default, although we've been using
SGen for our commercial products (which is why we feel that SGen is now ready
to be the default).

