Outline of Class 36: Other Machine-Level Issues
Held: Tuesday, April 7, 1998
- It appears that I'm unable to read chapter numbers. You should have
read Chapter 7 for tomorrow (ho ho ho).
- You should read Chapter 8 for Friday.
- Any questions on
Don't forget that it's due tomorrow. Don't write your own tester!
Use mine. You can find the source code for the tester in
- I've made a last-minute update to the syllabus (I decided to add a
little bit more on machine-level issues), so my notes for
today are probably even less accurate and copious than is my standard.
- We may have prospectives visiting the class on Friday. Treat them
- How might we store more complex information, such as images?
- As you probably know, most images are broken down into a grid of
pixels (small dots).
- In a black-and-white image, the pixels are black and white.
- In a greyscale image, the pixels are some shade of grey (usually
one of 256 greys).
- In a color image, the pixels are in color.
- Representing these types of images requires us to consider two
- How do we represent groups of pixels?
- How do we represent the individual pixel colors?
- The easiest representation is to write the value of each pixel in
sequence (along with some notation as to the size of the image).
- However, this requires a lot of space.
- Another possibility is to look for sequences of identical pixels
and write down the value of one pixel and then the length of the
sequence. In many images, this provides significant
compression of the image.
- Traditionally, black-and-white images are represented with a single
bit per pixel.
- Greyscale images are usually represented with one byte per pixel
(all 0's is white, all 1's is black, or vice-versa).
- There are a number of basic strategies for color images.
- In 24-bit RGB color, one byte is used for each of three colors
(red, green, and blue) that then determine the color of the pixel.
- In indexed color, a color table lists the colors used in
the image (usually 256 separate RGB values) and each pixel has a
byte that serves as an index into the table.
- How do we store objects in memory? Usually, as a grouped collection
of the fields in the object plus a reference to the methods.
I'll draw a picture.
- Note that inheritance is handled at compile time rather than
run time. That is, all the fields in a superclass are included within
the object of the subclass (separate objects are not created).
- The same is true of methods.
- How is memory arranged in the computer while the program is running?
Usually into three parts:
- Static memory
- The stack
- The heap
- (This stack and heap are somewhat different from the data structures
we will soon learn about.)
- As you might guess, static memory is reserved for things
that don't really change, such as program code. Often, the most
general variables (e.g., those in main) are also stored in
- The stack and the heap provide what is normally called
dynamic memory. This is where new objects (and other things)
are allocated and deallocated.
- The heap is where most objects are created. It is an unordered
"chunk" of memory. When a new object is requested, some part of that
chunk is then used for the object. When the object is no longer needed
(and either explicitly deallocated or garbage collected by the system),
it is freed up for the next object to be allocated.
- The stack is where local variables for procedures (and
other information on procedures) normally go. When you call a procedure,
a stack frame is created containing the parameters for the
procedure as well as any local variables. The stack frame also contains
information on the previous stack frame and an indication of where in
the previous procedure we were.
- When the procedure terminates, we return to the previous stack frame.
- In most modern languages, it is possible to dynamically create new
objects (or variables or ...).
- This can lead to problems: what happens when we're done with something
we've created? We can't just leave it around, or we'll eventually
run out of memory.
- In many languages (C, C++, Pascal, etc.), programmers are responsible
for reclaiming the memory allocated to objects they've created.
- This can lead to many problems
- Some people reclaim memory that's still in use.
- Some people forget to reclaim memory that's no longer in use.
- I've been told that for professional programmers, over 50% of
debugging time is devoted to problems related to memory allocation.
- To reduce these problems, many modern languages now provide automatic
garbage collection. That is, the implementation of the
language automatically determines which allocated things are no
longer necessary and frees them up.
- There are a number of strategies for garbage collection. They include:
- Reference count: associate a counter with each object. When
a new reference is made to the object, increment the counter. When
a reference is moved to another object, decrement the counter. When
you reach 0, delete the object.
- Mark and sweep: mark all the active things, then sweep through
memory noting what is now free.
- Copying: identify all the active objects, copy them
elsewhere in memory, and update all the references to them.