Memory and address space
Each process running on the computer gets its own "view" of memory.
This is its memory address space.
For
example, on a 32-bit computer, each process can see a maximum of 232 bytes,
or 4GB. In fact, a particular operating system will usually impose further
constraints, because a running process needs to be able to some memory that
isn't actually part of that process: access operating
system routines, drivers, I/O memory buffers etc. So for example, on most
32-bit versions of Windows, a process can allocate up to 2GB of its own "user" memory
(user space)
and the other 2GB of memory space is reserved for so-called kernel space—
the other things allocated by the operating system that we mentioned.
On Linux and Solaris, the split is usually 3GB of user space to 1GB of kernel space.
On a 64-bit computer, the same principle applies, but the amounts of memory involved
are huge by today's standards. The total memory space of a process is 264,
or about 16 million terabytes; whatever split you make between user and kernal space,
neither will generally run out of space for the forseeable future.
It's important to note that each process gets its own view of memory, often
called logical memory, and that this isn't the same as physical memory.
So for example, a block of memory starting at address
0x8000, it it is used, will be mapped to some area of physical memory.
If Process B accesses address 0x8000, it will be accessing a different
area of physical memory to Process A. The OS and the processor's memory management unit
handle that mapping. If there isn't enough physical memoory to go round for all the
logical memory that different processes want to allocate simultaneously, then
the virtual memory swaps areas in and out of physical memory to the hard
drive.
Technically, a process is a unit of execution that has its own
memory space. In simple terms, that means that its memory is kept separate
from that of other processes. Process A could arrange to send some data to Process B,
but it generally can't just go and read Process B's memory directly. There is also
a limit on the amount of memory that each process can "see" or address
(see box opposite).
A thread, on the other hand, is a sub-unit of a process,
and shares the memory space of that process. The different threads running
in a program (process) can read each other's memory. Indeed, many of the
thread synchronization and concurrency problems that we need to
think about happen precisely because threads see each other's memory.
Launching a separate process
Often, our informal notion of a process being a "program" coincides with the technical
definition of a process being a separate unit with its own memory space. But sometimes
they can depart from one another. The reason for this is that one process can launch
another process, sometimes called a child process. There are a
couple of common reasons for why this is useful:
- we may need to run a separate program that provides some
auxiliary function (or because our own program has been split into several
processes simply as a design decision)— for example, we might need to
call a system command that sends an e-mail or controls the disk
defragmenter;
- on 32-bit operating systems, to get around the memory-per-process limit.
A 64-bit operating systems become the norm, the first of these reasons will
overshadow the second, and is essentially the case that we'll be discussing in
this section.
How to launch a process in Java
To launch a process, Java has two classes two help us out:
- the Process class represents a running process (or
one that we've run and has now terminated);
- the ProcessBuilder class encapsulates the parameters
of a process that we're about to start.
On the next page, we look at the Process and ProcessBuilder classes.