Re: C++ Frequently Questioned Answers
* Yossi Kreinin:
On Nov 3, 4:42 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Yossi Kreinin:
Non-intrusive garbage collectors have false positives (some things
look like pointers, but aren't), and fail when people use formally
illegal, but normally working techniques like int* one_based_vector =
(int*)malloc(sz)-1;
I hope James will answer that.
Well, this is a widely acknowledged fact, for example:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.27
How much of a problem false positives are in practice can only be
answered by experience, and I lack experience with GC in C++.
So I hope James Kanze will answer that.
[snip]
One thing C++ garbage collectors can't do is heap compaction. AFAIK
this increases the upper bound on the memory consumed by a program
with the peak sum of allocated object sizes equal to M from M to
M*log(max_block_size), which is a huge difference for realistic values
of max_block_size.
There is nary a computer science problem that can't be solved by
adding a level of indirection. Modern computers typically have built-
in memory management that adds just such a level of indirection. In
the old days before that hardware became commonplace on PC's we had to
use handles to memory (instead of direct pointers), in order to allow
compaction.
Many systems (/exactly/ the kind where garbage collection would be
problematic due to real time requirements) lack paging...
But then paging doesn't really solve this problem. It's enough to have
a single byte occupied inside a page to make it impossible to dispose
it; with fragmentation, you end up exactly with this problem - little
objects scattered across the memory.
With a single byte allocated that logical address can just be mapped to
some other page.
But even if you have paging and entire free pages, I don't think most
real OSes will actually reclaim the page. malloc typically runs on top
of something like sbrk(), which manages a stack - you can yank more
pages or reclaim pages at the end of the data segment, but you can't
free the pages in the middle of the data segment. At best, the pages
at the middle will be eventually swapped out, littering the disk
instead of the RAM (and some systems with virtual memory are
diskless).
This is an OS problem, not a language or C++ or GC problem.
With extreme fragmentation and large underlying page size it would be
possible to consume a lot of memory, as opposed to address space.
However, I don't think that's something that a language solves for you.
I think it does, by making it possible to do automatic heap
compaction. If a language is built such that the run time knows where
all the pointers are and can update them upon heap compaction, the
problem is solved; so I do think it's a "linguistic" issue, not a
"systems" issue.
Most probably incurring the Long Inconvenient Pause (LIP (TM))...
[snip]
Unpredictable and jerky response time is one consideration, yes.
Garbage collection isn't necessarily slower than manual memory
management:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.26
Who said it was slower? But right above you argued that having the GC
system update pointer values in order to compact the heap, is a nice
feature. Well, for a small app that finishes before any heap compaction
is invoked, one may simply rely on the OS freeing memory on process
termination, whereas with an application that does run until heap
compaction occurs, the general performance of GC is at least arguable.
Anyways, performance isn't a main general reason to avoid (modern) GC.
[snip]
But
I was mainly thinking of the impact on design when objects hold
references to non-memory resources. In e.g. Java this leads to
"destroy" methods all over the place, where a call to such a method
zombifies the object. This in turns leads to checks of whether the
object is a zombie, resulting in complication, and undetected invalid
usage of the zombified object.
C# helps a little with its "using" statement, but that's mostly
cosmetic.
Here's why memory is very different from other resources:
[snip]
Overall, I think this justifies special treatment of memory.
Yes.
[snip]
You mean the kind of object created by "std::ifstream in;"?
Yes, technically.
However, a file object is different from the Bad Zombie in two important
ways. First, it encapsulates an abstraction that itself has zombie
characteristics: the complication is not added, but is inherent in the
problem domain (it can be simplified and made safer only by applying
Intelligent Design (TM) ;-) -- which unfortunately wasn't done for the
standard library's iostreams, which are ugly stinkin' beasts indeed).
Second, you don't allocate a file object dynamically and refer to it via
pointers, you allocate it on the stack or in some other object, where
its zombiness isn't that much of a /serious/ problem, just a localized
major pain.
Of these two points the first is the most important: with GC you get a
lot of zombies resulting not from inherent zombieness in the problem
domains but from the programmers' GC-oriented way of doing cleanup, and
as someone else remarked else-thread, this zombieness then propagates up
through the object hierarchy so that it's eventually imposed on much of
the system, and mostly it's easily avoidable with C++ RAII.
Yes, that's a different kind of "zombie"...
Uh, no, std::ifstream() is a zombie all right, except the Bad Zombie, as
explained above, is much worse to handle, has a general negative impact
on the rest of the system (propagating zombieness, adding complexity and
attracting incorrect usage) and is much worse in the sense that in
general it's completely unnecessary, easily avoidable with RAII.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]