1
|
1 |
"
|
5
|
2 |
COPYRIGHT (c) 1992 by Claus Gittinger
|
159
|
3 |
All Rights Reserved
|
1
|
4 |
|
|
5 |
This software is furnished under a license and may be used
|
|
6 |
only in accordance with the terms of that license and with the
|
|
7 |
inclusion of the above copyright notice. This software may not
|
|
8 |
be provided or otherwise made available to, or used by, any
|
|
9 |
other person. No title to or ownership of the software is
|
|
10 |
hereby transferred.
|
|
11 |
"
|
|
12 |
|
|
13 |
Object subclass:#ObjectMemory
|
|
14 |
instanceVariableNames:''
|
2
|
15 |
classVariableNames:'InternalErrorHandler UserInterruptHandler TimerInterruptHandler
|
159
|
16 |
SpyInterruptHandler StepInterruptHandler ExceptionInterruptHandler
|
|
17 |
ErrorInterruptHandler MemoryInterruptHandler SignalInterruptHandler
|
|
18 |
ChildSignalInterruptHandler DisposeInterruptHandler
|
|
19 |
RecursionInterruptHandler IOInterruptHandler
|
|
20 |
CustomInterruptHandler
|
345
|
21 |
RegisteredErrorInterruptHandlers
|
2
|
22 |
|
178
|
23 |
AllocationFailureSignal LowSpaceSemaphore
|
310
|
24 |
IncrementalGCLimit FreeSpaceGCLimit FreeSpaceGCAmount
|
290
|
25 |
BackgroundCollectProcess BackgroundFinalizationProcess
|
|
26 |
FinalizationSemaphore
|
159
|
27 |
Dependents
|
|
28 |
ImageName'
|
1
|
29 |
poolDictionaries:''
|
|
30 |
category:'System-Support'
|
|
31 |
!
|
|
32 |
|
|
33 |
ObjectMemory comment:'
|
5
|
34 |
COPYRIGHT (c) 1992 by Claus Gittinger
|
159
|
35 |
All Rights Reserved
|
93
|
36 |
|
370
|
37 |
$Header: /cvs/stx/stx/libbasic/Attic/ObjMem.st,v 1.48 1995-08-03 01:15:54 claus Exp $
|
2
|
38 |
'!
|
|
39 |
|
|
40 |
!ObjectMemory class methodsFor:'documentation'!
|
|
41 |
|
88
|
42 |
copyright
|
|
43 |
"
|
|
44 |
COPYRIGHT (c) 1992 by Claus Gittinger
|
159
|
45 |
All Rights Reserved
|
88
|
46 |
|
|
47 |
This software is furnished under a license and may be used
|
|
48 |
only in accordance with the terms of that license and with the
|
|
49 |
inclusion of the above copyright notice. This software may not
|
|
50 |
be provided or otherwise made available to, or used by, any
|
|
51 |
other person. No title to or ownership of the software is
|
|
52 |
hereby transferred.
|
|
53 |
"
|
|
54 |
!
|
|
55 |
|
|
56 |
version
|
|
57 |
"
|
370
|
58 |
$Header: /cvs/stx/stx/libbasic/Attic/ObjMem.st,v 1.48 1995-08-03 01:15:54 claus Exp $
|
88
|
59 |
"
|
|
60 |
!
|
|
61 |
|
2
|
62 |
documentation
|
|
63 |
"
|
68
|
64 |
This class contains access methods to the system memory -
|
|
65 |
in previous versions this stuff used to be in the Smalltalk class.
|
|
66 |
It has been separated for better overall structure.
|
229
|
67 |
There are no instances of ObjectMemory - all is done in class methods.
|
1
|
68 |
|
68
|
69 |
Many methods here are for debuging purposes only, and not standard.
|
|
70 |
Do not depend on them being there - some may vanish ...
|
|
71 |
(especially those, that depend on a specific GC implementation)
|
13
|
72 |
|
229
|
73 |
Warning:
|
|
74 |
The InterruptHandler variables are known by the runtime system -
|
|
75 |
they are the objects that get an interrupt message when the event
|
|
76 |
occurs. You may not remove them.
|
2
|
77 |
|
229
|
78 |
Class variables:
|
2
|
79 |
|
159
|
80 |
InternalErrorHandler gets informed (by VM), when some runtime
|
|
81 |
error occurs (usually fatal)
|
2
|
82 |
|
159
|
83 |
UserInterruptHandler gets informed (by VM) when CNTL-C is pressed
|
|
84 |
TimerInterruptHandler gets alarm timer interrupts (from VM)
|
|
85 |
SpyInterruptHandler another alarm timer (from VM)
|
|
86 |
StepInterruptHandler gets single step interrupts (from VM)
|
|
87 |
ExceptionInterruptHandler gets floating point exceptions (from VM)
|
345
|
88 |
ErrorInterruptHandler gets primitive errors (from VM)
|
159
|
89 |
MemoryInterruptHandler gets soon-out-of-memory conditions (from VM)
|
|
90 |
SignalInterruptHandler gets unix signals (from VM)
|
|
91 |
ChildSignalInterruptHandler gets child death signals (from VM)
|
|
92 |
DisposeInterruptHandler gets informed, when an object is disposed from
|
|
93 |
a shadowArray (from VM)
|
|
94 |
RecursionInterruptHandler gets recursion limit violations (from VM)
|
|
95 |
IOInterruptHandler gets SIGIO unix signals (from VM)
|
|
96 |
CustomInterruptHandler gets custom interrupts (from VM)
|
2
|
97 |
|
345
|
98 |
RegisteredErrorInterruptHandlers
|
|
99 |
associates errorID (as passed from primitive
|
|
100 |
to the __errorInterruptWithID() function)
|
|
101 |
with handlers.
|
|
102 |
|
270
|
103 |
IncrementalGCLimit number of bytes, that must be allocated since
|
290
|
104 |
last full garbage collect to turn the incremental
|
|
105 |
collector on (at idle time).
|
|
106 |
|
|
107 |
FreeSpaceGCLimit low limit on freeSpace at which incremental
|
|
108 |
gc starts to run at idle time.
|
270
|
109 |
|
310
|
110 |
FreeSpaceGCAmount amount to allocate once freeSpace drops
|
|
111 |
below FreeSpaceGCLimit
|
|
112 |
|
159
|
113 |
Dependents keep my dependents locally (its faster) for
|
|
114 |
all those registries
|
270
|
115 |
|
213
|
116 |
LowSpaceSemaphore a semaphore signalled whenever the system is
|
|
117 |
running in low memory (i.e. the memory manager
|
|
118 |
ran into memory shortage and feels that it
|
|
119 |
may soon be no longer grant allocation requests).
|
|
120 |
You can have a process waiting on this semaphore
|
|
121 |
which starts to remove (i.e. nil-out) objects
|
|
122 |
or preform other cleanup actions.
|
|
123 |
|
|
124 |
AllocationFailureSignal signal raised when a new fails (see Behavior)
|
|
125 |
When this signal is raised, the meomory manager
|
|
126 |
is really in trouble (i.e. above feelings where
|
|
127 |
correct)
|
290
|
128 |
|
|
129 |
BackgroundCollectProcess created by startBackgroundCollectorAt:
|
|
130 |
|
|
131 |
BackgroundFinalizationProcess created by startBackgroundFinalizationAt:
|
2
|
132 |
"
|
93
|
133 |
!
|
|
134 |
|
|
135 |
caching
|
|
136 |
"
|
|
137 |
The system uses various caches to speed up method-lookup.
|
|
138 |
Currently, there is a three-level cache hierarchy:
|
|
139 |
|
159
|
140 |
inline-cache keeps the target of the last send at the caller-
|
|
141 |
side (i.e. every send goes through its private
|
|
142 |
1-slot inline-cache, where the address of the last
|
|
143 |
called function at this call location is kept.)
|
93
|
144 |
|
229
|
145 |
polymorph-inline-cache keeps a limited list of all targets ever reached
|
|
146 |
at this call location. The list is automatically
|
|
147 |
flushed if it grows too large, or the overall number
|
|
148 |
of poly-chache entries exceeds a limit.
|
93
|
149 |
|
159
|
150 |
method-lookup-cache a global cache. Hashes on class-selector pairs,
|
|
151 |
returning the target method.
|
93
|
152 |
|
|
153 |
Whenever methods are added or removed from the system, or the inheritance
|
|
154 |
hierarchy changes, some or all caches have to be flushed.
|
202
|
155 |
The flushXXX methods perform the task of flushing various caches.
|
207
|
156 |
All standard methods in Behavior call for cache flushing, when things change;
|
229
|
157 |
however, if you use the low level access methods in Behavior
|
|
158 |
(for example: #setSuperclass:) special care has to be taken.
|
|
159 |
|
|
160 |
In some situations, not all caches need flushing, for example a change
|
|
161 |
in an interpreted method (currently) needs no flushing of the inline caches.
|
|
162 |
Also, flushing can be limited to entries for a specific class for most changes.
|
|
163 |
|
202
|
164 |
To be 'on the brigth side of live', use ObjectMemory>>flushCaches (which
|
|
165 |
flushes all of them), when in doubt of which caches should be flushed.
|
|
166 |
It is better flush too much - otherwise you may end up in a wrong method after
|
|
167 |
a send.
|
93
|
168 |
"
|
|
169 |
!
|
|
170 |
|
|
171 |
interrupts
|
|
172 |
"
|
|
173 |
Handling of interrupts (i.e. unix-signals) is done via handler objects, which
|
|
174 |
get a #XXXInterrupt-message sent. This is more flexible than (say) signalling
|
|
175 |
a semaphore, since the handler-object may do anything to react on the signal
|
|
176 |
(of course, it can also signal a semaphore to emulate the above behavior).
|
|
177 |
|
229
|
178 |
Another reason for having handler objects is that they allow interrupt handling
|
207
|
179 |
without any context switch, for high speed interrupt response.
|
|
180 |
However, special care is needed, since it is not defined, which process gets
|
|
181 |
the interrupt and will do the processing.
|
93
|
182 |
Typically, the handlers are set during early initialization of the system
|
202
|
183 |
by sending 'ObjectMemory XXXInterruptHandler:aHandler' and not changed later.
|
|
184 |
(see Smalltalk>>initialize or ProcessorScheduler>>initialize).
|
207
|
185 |
To setup your own handler, create some object which responds to #xxxInterrupt,
|
|
186 |
and make it the handler using the above method.
|
|
187 |
|
|
188 |
Interrupt messages sent to handlers are:
|
|
189 |
internalError:<someString> - internal interpreter/GC errors
|
|
190 |
userInterrupt - ^C interrupt
|
|
191 |
customInterrupt - custom interrupt
|
|
192 |
ioInterrupt - SIGIO interrupt
|
229
|
193 |
timerInterrupt - alarm timer (SIGALRM)
|
345
|
194 |
errorInterrupt:<id> - errors from other primitives/subsystems
|
|
195 |
(DisplayError)
|
229
|
196 |
spyInterrupt - spy timer interrupt (SIGVTALARM)
|
207
|
197 |
stepInterrupt - single step interrupt
|
|
198 |
disposeInterrupt - finalization required
|
|
199 |
recursionInterrupt - recursion (stack) overflow
|
|
200 |
memoryInterrupt - soon running out of memory
|
229
|
201 |
fpExceptionInterrupt - floating point exception (SIGFPE)
|
207
|
202 |
childSignalInterrupt - death of a child process (SIGCHILD)
|
|
203 |
signalInterrupt:<number> - unix signal (if other than above signals)
|
93
|
204 |
"
|
|
205 |
!
|
|
206 |
|
|
207 |
garbageCollection
|
|
208 |
"
|
|
209 |
Currently, Smalltalk/X uses a two-level memory hierachy.
|
|
210 |
Objects are created in a so-called newSpace, which is relatively small.
|
202
|
211 |
This newSpace is cleaned by a scavenge-operation, whenever becoming
|
133
|
212 |
full. Scavenging means, that all still-live objects (i.e. referenced by some
|
|
213 |
other) are copied over to another memory area, leaving all unreferenced
|
207
|
214 |
objects as garbage behind. After this copying, these two semispaces exchange their
|
202
|
215 |
roles - i.e. objects are copied ping-pong like between these semispaces.
|
|
216 |
Once an object survives enough of these copying operations, the next scavenge
|
216
|
217 |
will move it into the so called oldSpace, which is much larger, and not
|
202
|
218 |
processed by the scavenger.
|
|
219 |
This movement of an object from newSpace to oldSpace is called 'tenure'.
|
133
|
220 |
|
93
|
221 |
Scavenging occurs automatically, and is usually done fast enough to go
|
|
222 |
unnoticed (typically, it takes some 5 to 50ms to perform a scavenge,
|
|
223 |
depending on how many live objects are in the newspace).
|
|
224 |
Interrestingly, the scavenger performs better, if many garbage objects
|
|
225 |
are to be reclaimed, since less object-copying has to be done. Therefore,
|
216
|
226 |
the best-case scavenge time is almost zero, if there is only garbage in
|
|
227 |
the newSpace. In contrast, the worst-case is when all newSpace objects are still
|
207
|
228 |
living. To honor this situation, the system uses an adaptive tenure-count,
|
|
229 |
which adjusts the number of scavenges required for tenure (the so called
|
|
230 |
'tenureAge') according to the fill-grade of the newSpace.
|
93
|
231 |
|
|
232 |
To reclaim oldspace, the system uses three algorithms: mark&sweep, a copying
|
|
233 |
(and compressing) baker-type collector and an incremental mark&sweep.
|
|
234 |
|
|
235 |
The mark&sweep runs whenever the oldspace becomes full, putting dead objects
|
|
236 |
onto a free list. If a memory request cannot be served from this freelist,
|
|
237 |
and the total size of objects on the freelist exceeds a threshold, the system
|
|
238 |
will compress the oldspace to make the free-space into one big area.
|
207
|
239 |
This compress is done by copying all live objects into a newly allocated
|
|
240 |
area, and freeing the previous memory afterwards (baker collector).
|
93
|
241 |
Since a compressing oldspace collect leads to a noticable pause of the system,
|
|
242 |
the memory manager tries hard to avoid oldspace compression.
|
207
|
243 |
(actually, if enough real memory is available to hold both spaces in physical
|
|
244 |
memory, the compress is pretty fast).
|
202
|
245 |
|
93
|
246 |
The incremental mark&sweep runs in the background, whenever the system is idle
|
362
|
247 |
(see ProcessorSceduler>>waitForEventOrTimeout), or alternatively as a low priority
|
|
248 |
background process (see ObjectMemory>>startBackgroundCollector).
|
|
249 |
Like the normal mark&sweep, this incremental collector follows object references
|
|
250 |
and marks reachable objects on its way. However, this is done 'a few objects-at-a-time',
|
|
251 |
to not disrupt the system noticably. Currently, there are some (theoretical) and in
|
|
252 |
practice never occurring situations, in which the incremental GC still creates delays
|
|
253 |
longer than a few milliseconds. A current project is involved with this and a future
|
|
254 |
versions of ST/X (ST/X-RT) will be available which shows deterministic worst case
|
|
255 |
behavior in its GC pauses (this will be provided as an additional add-on option).
|
|
256 |
|
|
257 |
Incremental garbage collection is controlled by the variables
|
|
258 |
'IncrementalGCLimit', 'FreeSpaceGCLimit' and 'FreeSpaceGCAmount':
|
310
|
259 |
|
290
|
260 |
the ProcessorScheduler will perform incremental GC steps at idle time,
|
|
261 |
if the total space allocated since the last full collect exceeds
|
362
|
262 |
'IncrementalGCLimit',
|
290
|
263 |
or if there are less than 'FreeSpaceGCLimit' bytes available in free store.
|
362
|
264 |
If after the incrementalGC, less than 'FreeSpaceGCLimi't bytes are available,
|
310
|
265 |
'FreeSpaceGCAmount' more bytes are requested from the memory manager.
|
290
|
266 |
|
|
267 |
The defaults are set in ObjectMemory>>initialize and can be changed in your
|
|
268 |
startup 'smalltalk.rc'-file. Setting them to nil will turn incremental GC off.
|
270
|
269 |
|
362
|
270 |
For example, setting 'IncrementalGCLimit' to 500000 will start the background collector
|
207
|
271 |
whenever 500k bytes have been allocated - usually very seldom. Setting it to some
|
|
272 |
small number (say 10000) will have it run very often.
|
290
|
273 |
|
362
|
274 |
Setting 'FreeSpaceGCAmount' to (say) 1meg lets the system try to always keep
|
290
|
275 |
1meg of freeSpace. If less memory is available, more oldSPace will be allocated
|
|
276 |
for. This may prevent the system from running into a GC pause when memory is
|
|
277 |
allocated in peaks (but only, if the incremental GC can keep up with allocation
|
362
|
278 |
rate). The trigger level 'FreeSpaceGCLimit' should be below that amount;
|
310
|
279 |
to avoid excessive incremental GC activity (say 1/4 if the amount).
|
290
|
280 |
|
|
281 |
Having the background GC running often should not hurt the performance of your
|
362
|
282 |
smalltalk processes, since the IGC only runs at times when no ST processes are runnable.
|
290
|
283 |
(there are some short delays in event processing, since the IGC's steps may take
|
|
284 |
some XX ms.)
|
270
|
285 |
However, if you are not alone on your machine (i.e. a timesharing system) or
|
|
286 |
you have other Unix processes to run, you should not run the IGC too often,
|
362
|
287 |
since it may hurt OTHER users/unix processes.
|
93
|
288 |
|
216
|
289 |
Since this collector only runs at idle times, even a low priority background
|
|
290 |
process will prevent it from doing its work. You may want to start a somewhat
|
207
|
291 |
higher priority background collect (say at prio 4), which also preempts these
|
|
292 |
background processes. (see ObjectMemory>>startBackgroundCollectorAt:).
|
202
|
293 |
|
325
|
294 |
Beginning with 2.10.4, a third space, called symSpace has been added.
|
216
|
295 |
Objects in this space are never moved or garbage collected.
|
325
|
296 |
This space is used for (some) symbols only.
|
|
297 |
|
|
298 |
Beginning with 2.10.5, a fourth space, called fixSpace has been added.
|
|
299 |
Objects in this space are never moved or garbage collected.
|
|
300 |
This space is used for constant objects (true, false, some basic classes etc.).
|
229
|
301 |
|
|
302 |
A plan for 2.11 is to offer an arbitrary number of spaces, which can be
|
|
303 |
attached and detached at runtime. This will allow easy share of object
|
|
304 |
with remote systems and separating objects into a per application/package
|
|
305 |
space. (be prepared for changes in the future and make your application
|
|
306 |
independ of the VM internals)
|
216
|
307 |
|
202
|
308 |
hints & tricks:
|
|
309 |
|
213
|
310 |
normally, there is no need to call for an explicit garbage collection, or
|
216
|
311 |
modify the default parameters.
|
213
|
312 |
The memory system should adapt reasonable and provide good performance
|
202
|
313 |
for a wide range of allocation patterns (see Example3 below for an exception).
|
|
314 |
|
207
|
315 |
However, there may be situations, in which hints and/or explicit
|
202
|
316 |
control over allocation can speedup your programs; but please:
|
93
|
317 |
|
207
|
318 |
- if you think you have to play around with the memory policies,
|
202
|
319 |
first check your program - you may find useless allocations
|
|
320 |
or bad uses of collections. A typical error that is made is to
|
|
321 |
create large collections using the #, (comma) concatenation method,
|
|
322 |
which shows square behavior, since it allocates many, many temporary
|
213
|
323 |
collections. Also, watch out for #copyWith:, #add: etc.
|
202
|
324 |
All of these create a new collection. Remember, that most collections
|
|
325 |
offer methods to preallocate some space; for example, 'Set new:' creates
|
229
|
326 |
an empty set, but preallocates space to avoid resizing over and over.
|
|
327 |
|
216
|
328 |
An especially bad performace dog is to use #add: on fix-size collection
|
|
329 |
objects (such as Strings or Arrays), since in addition to allocating
|
229
|
330 |
lots of garbage, a #become: operation is required for EACH element
|
216
|
331 |
added. NEVER use Arrays for growing/shrinking data - use OrderedCollection
|
229
|
332 |
instead. (if you really need an array, use asArray afterwards)
|
202
|
333 |
|
207
|
334 |
- if you are going to allocate huge data structures, think about
|
|
335 |
optimizing space. For example, if you allocate a million instances of
|
213
|
336 |
some object, each added instance variable makes up 4Mb of additional
|
|
337 |
memory need.
|
207
|
338 |
Also, for Byte-valued, Integer-valued and Float like objects, special
|
|
339 |
collections are provided, which store their values directly inside (instead
|
|
340 |
of a reference to the object). A FloatArray consisting of 1 million floats
|
213
|
341 |
requires about 4mb of memory, while an Array of Floats requires 4mb for the
|
|
342 |
references to the floats, PLUS 20Mb for the floats themself.
|
93
|
343 |
|
207
|
344 |
- check if you really need fast access to all of these objects; you may
|
|
345 |
try to only keep some subset in memory, and use binary storage or
|
|
346 |
(if this is too slow) optimized store/retrieve methods and keep the bigger
|
229
|
347 |
part in a file.
|
362
|
348 |
(How about a DiskArray class, which does this transparently ?
|
229
|
349 |
See the FileText class for some ideas and something to start with ...)
|
207
|
350 |
|
|
351 |
|
|
352 |
Hint / Example 1:
|
93
|
353 |
you are about to allocate a huge data structure, which is known to
|
|
354 |
survive long. In this case, it is better to have these objects move into the
|
|
355 |
oldspace sooner, to avoid the copying overhead during scavenges.
|
|
356 |
|
|
357 |
To do this, you can call ObjectMemory>>tenure after allocation, which
|
|
358 |
forces all new-objects immediately into the oldspace.
|
|
359 |
Make certain, that not to many (ideally no) short-living objects are in the
|
|
360 |
newspace when doing this.
|
|
361 |
|
|
362 |
Another alternative is to tell the system that all allocation should be
|
|
363 |
done directly in the oldspace. This completely avoids the scavenging overhead
|
|
364 |
for these objects. To do so, use ObjectMemory>>turnGarbageCollectorOff
|
|
365 |
before the allocation, and ObjectMemory>>turnGarbageCollectorOn afterwards.
|
202
|
366 |
Keep in mind, that do-loops may allocate block-objects and other temporaries,
|
178
|
367 |
so there is a danger of making things worse due to having all those temporaries
|
93
|
368 |
in the oldspace afterwards. (which is not a fatal situation, but will
|
178
|
369 |
force the system to do an oldspace collect earlier, which may not be your
|
|
370 |
intention).
|
93
|
371 |
|
202
|
372 |
|
207
|
373 |
Hint / Example 2:
|
93
|
374 |
you know in advance, that a certain (big) amount of memory will be needed.
|
|
375 |
For example, the fileBrowser wants to show a huge file in its text-view.
|
133
|
376 |
In this case, it is better to tell the memory system in advance, how much
|
93
|
377 |
memory will be needed, since otherwise many compresses and reallocations will
|
133
|
378 |
occur (the memory system will allocate additional memory in chunks of smaller
|
|
379 |
256k pieces, if a compress failes. Thus, if you are going to allocate (say) 1Mb of
|
|
380 |
strings, it will perform 5 compressing GC's).
|
|
381 |
|
202
|
382 |
This is done using ObjectMemory>>moreOldSpace: or ObjectMemory announceSpaceNeed:.
|
|
383 |
In the above example, you would do 'ObjectMemory announceSpaceNeed:500000', which
|
133
|
384 |
avoids those annoying 5 compressing GC's.
|
207
|
385 |
BTW: if you have other smalltalk processes (threads) running which should not be
|
|
386 |
paused if possible, it is better to use #announceSpaceNeed. This tries to avoid
|
|
387 |
pausing in other processes and sometimes succeeds, while moreOldSpace will always
|
|
388 |
block the whole system for a while. However, there is no 'no-pause' guarantee.
|
133
|
389 |
|
|
390 |
The amount of automatic increase (in case the oldSpace becomes full) is 256k by
|
|
391 |
default. This number can be changed with ObjectMemory>>oldSpaceIncrement:.
|
|
392 |
|
207
|
393 |
|
|
394 |
Hint / Example3:
|
178
|
395 |
There are rare cases, when an explicit GC makes a difference: since
|
|
396 |
object finalization is done at GC time, objects which keep operatingSystem
|
|
397 |
resources may be finalized late. This is normally no problem, except if
|
|
398 |
the system is running out of resources. For example, allocating new colors
|
|
399 |
may fail if many colors have already been allocated in the past - even
|
|
400 |
though these colors are actually free. The Depth8Image calls for an
|
|
401 |
explicit GC, whenever it fails to allocate a color for a bitmap, to force
|
|
402 |
finalization of free, but not yet finalized colors.
|
|
403 |
|
207
|
404 |
|
|
405 |
Hint 4:
|
|
406 |
If you run in too small of physical memory, the incremental GC may have a
|
|
407 |
bad effect on your working set: since it touches pages (which may otherwise
|
|
408 |
not be needed at the moment, the operating system is forced to steal other
|
|
409 |
(possibly more useful) pages from your set of incore pages.
|
|
410 |
You may get better performance, if you turn off the incremental GC while
|
|
411 |
processing a big data structure.
|
|
412 |
|
|
413 |
|
229
|
414 |
Warning: many of the methods found here are not standard and may not even be available in
|
133
|
415 |
future versions of ST/X. Use them only in very special situations or experiments.
|
229
|
416 |
|
207
|
417 |
Let me know about additional special features you think are useful, and about
|
|
418 |
special features you are using - this provides the feedback required to decide
|
|
419 |
which methods are to be removed or kept or enhanced in future versions.
|
93
|
420 |
"
|
2
|
421 |
! !
|
|
422 |
|
|
423 |
!ObjectMemory class methodsFor:'initialization'!
|
|
424 |
|
|
425 |
initialize
|
178
|
426 |
"initialize the class"
|
|
427 |
|
2
|
428 |
AllocationFailureSignal isNil ifTrue:[
|
302
|
429 |
AllocationFailureSignal := ErrorSignal newSignalMayProceed:true.
|
159
|
430 |
AllocationFailureSignal nameClass:self message:#allocationFailureSignal.
|
|
431 |
AllocationFailureSignal notifierString:'allocation failure'.
|
178
|
432 |
|
|
433 |
LowSpaceSemaphore := Semaphore new.
|
2
|
434 |
].
|
290
|
435 |
DisposeInterruptHandler := self.
|
2
|
436 |
IncrementalGCLimit := 500000.
|
310
|
437 |
FreeSpaceGCLimit := FreeSpaceGCAmount := nil.
|
13
|
438 |
MemoryInterruptHandler := self
|
2
|
439 |
! !
|
|
440 |
|
345
|
441 |
!ObjectMemory class methodsFor:'Signal constants'!
|
2
|
442 |
|
|
443 |
allocationFailureSignal
|
13
|
444 |
"return the signal raised when an object allocation failed"
|
|
445 |
|
2
|
446 |
^ AllocationFailureSignal
|
|
447 |
! !
|
1
|
448 |
|
178
|
449 |
!ObjectMemory class methodsFor:'semaphore access'!
|
|
450 |
|
|
451 |
lowSpaceSemaphore
|
|
452 |
"return the semaphore that is signalled when the system detects a
|
|
453 |
low space condition. Usually, some time after this, an allocationFailure
|
|
454 |
will happen. You can have a cleanup process sitting in that semaphore and
|
|
455 |
start to release object."
|
|
456 |
|
|
457 |
^ LowSpaceSemaphore
|
|
458 |
! !
|
|
459 |
|
10
|
460 |
!ObjectMemory class methodsFor:'dependents access'!
|
|
461 |
|
|
462 |
dependents
|
|
463 |
"return the colleciton of my dependents"
|
|
464 |
|
|
465 |
^ Dependents
|
|
466 |
!
|
|
467 |
|
|
468 |
dependents:aCollection
|
|
469 |
"set the dependents collection"
|
|
470 |
|
|
471 |
Dependents := aCollection
|
282
|
472 |
!
|
|
473 |
|
|
474 |
dependentsDo:aBlock
|
|
475 |
"evaluate aBlock for all of my dependents.
|
|
476 |
Since this is performed at startup time (under the scheduler),
|
|
477 |
this is redefined here to catch abort signals.
|
|
478 |
Thus, if any error occurs in a #returnFromSnapshot,
|
|
479 |
the user can press abort to continue."
|
|
480 |
|
|
481 |
|deps|
|
|
482 |
|
|
483 |
deps := Dependents.
|
|
484 |
deps notNil ifTrue:[
|
|
485 |
deps do:[:each |
|
|
486 |
AbortSignal handle:[:ex |
|
|
487 |
ex return
|
|
488 |
] do:[
|
|
489 |
aBlock value:each
|
|
490 |
]
|
|
491 |
]
|
|
492 |
]
|
10
|
493 |
! !
|
|
494 |
|
1
|
495 |
!ObjectMemory class methodsFor:'cache management'!
|
|
496 |
|
|
497 |
flushInlineCachesForClass:aClass
|
93
|
498 |
"flush inlinecaches for calls to aClass."
|
1
|
499 |
|
|
500 |
%{ /* NOCONTEXT */
|
|
501 |
__flushInlineCachesFor(aClass);
|
|
502 |
%}
|
|
503 |
!
|
|
504 |
|
|
505 |
flushInlineCachesWithArgs:nargs
|
|
506 |
"flush inlinecaches for calls with nargs arguments"
|
|
507 |
|
|
508 |
%{ /* NOCONTEXT */
|
|
509 |
__flushInlineCaches(_intVal(nargs));
|
|
510 |
%}
|
|
511 |
!
|
|
512 |
|
|
513 |
flushInlineCachesFor:aClass withArgs:nargs
|
|
514 |
"flush inlinecaches for calls to aClass with nargs arguments"
|
|
515 |
|
|
516 |
%{ /* NOCONTEXT */
|
|
517 |
__flushInlineCachesForAndNargs(aClass, _intVal(nargs));
|
|
518 |
%}
|
|
519 |
!
|
|
520 |
|
332
|
521 |
flushInlineCachesForSelector:aSelector
|
|
522 |
"flush inlinecaches for sends of aSelector"
|
|
523 |
|
|
524 |
%{ /* NOCONTEXT */
|
|
525 |
__flushInlineCachesForSelector(aSelector);
|
|
526 |
%}
|
|
527 |
!
|
|
528 |
|
1
|
529 |
flushInlineCaches
|
|
530 |
"flush all inlinecaches"
|
|
531 |
|
|
532 |
%{ /* NOCONTEXT */
|
|
533 |
__flushAllInlineCaches();
|
|
534 |
%}
|
|
535 |
!
|
|
536 |
|
|
537 |
flushMethodCacheFor:aClass
|
|
538 |
"flush the method cache for sends to aClass"
|
|
539 |
|
|
540 |
%{ /* NOCONTEXT */
|
|
541 |
__flushMethodCacheFor(aClass);
|
|
542 |
%}
|
|
543 |
!
|
|
544 |
|
332
|
545 |
flushMethodCacheForSelector:aSelector
|
|
546 |
"flush the method cache for sends of aSelector"
|
|
547 |
|
|
548 |
%{ /* NOCONTEXT */
|
|
549 |
__flushMethodCacheForSelector(aSelector);
|
|
550 |
%}
|
|
551 |
!
|
|
552 |
|
1
|
553 |
flushMethodCache
|
|
554 |
"flush the method cache"
|
|
555 |
|
|
556 |
%{ /* NOCONTEXT */
|
|
557 |
__flushMethodCache();
|
|
558 |
%}
|
|
559 |
!
|
|
560 |
|
2
|
561 |
flushCachesFor:aClass
|
|
562 |
"flush method and inline caches for aClass"
|
|
563 |
|
|
564 |
%{ /* NOCONTEXT */
|
|
565 |
__flushMethodCacheFor(aClass);
|
|
566 |
__flushInlineCachesFor(aClass);
|
|
567 |
%}
|
|
568 |
!
|
|
569 |
|
332
|
570 |
flushCachesForSelector:aSelector
|
|
571 |
"flush method and inline caches for aClass"
|
|
572 |
|
|
573 |
%{ /* NOCONTEXT */
|
|
574 |
__flushMethodCacheForSelector(aSelector);
|
|
575 |
__flushInlineCachesForSelector(aSelector);
|
|
576 |
%}
|
|
577 |
!
|
|
578 |
|
1
|
579 |
flushCaches
|
2
|
580 |
"flush method and inline caches for all classes"
|
1
|
581 |
|
|
582 |
%{ /* NOCONTEXT */
|
|
583 |
__flushMethodCache();
|
|
584 |
__flushAllInlineCaches();
|
|
585 |
%}
|
|
586 |
! !
|
|
587 |
|
216
|
588 |
!ObjectMemory class methodsFor:'enumerating'!
|
1
|
589 |
|
|
590 |
allObjectsDo:aBlock
|
85
|
591 |
"evaluate the argument, aBlock for all objects in the system.
|
|
592 |
There is one caveat: if a compressing oldSpace collect
|
|
593 |
occurs while looping over the objects, the loop cannot be
|
|
594 |
continued (for some internal reasons). In this case, false
|
|
595 |
is returned."
|
2
|
596 |
|
|
597 |
|work|
|
22
|
598 |
|
|
599 |
%{ /* NOREGISTER - work may not be placed into a register here */
|
326
|
600 |
__nonTenuringScavenge(__context);
|
2
|
601 |
/*
|
|
602 |
* allObjectsDo needs a temporary to hold newSpace objects
|
|
603 |
*/
|
369
|
604 |
if (__allInstancesOfDo((OBJ *)0, &aBlock, &work COMMA_CON) < 0) {
|
|
605 |
RETURN (false);
|
|
606 |
}
|
|
607 |
%}.
|
|
608 |
^ true
|
|
609 |
!
|
|
610 |
|
|
611 |
allInstancesOf:aClass do:aBlock
|
|
612 |
"evaluate the argument, aBlock for all instances of aClass in the system.
|
|
613 |
There is one caveat: if a compressing oldSpace collect
|
|
614 |
occurs while looping over the objects, the loop cannot be
|
|
615 |
continued (for some internal reasons). In this case, false
|
|
616 |
is returned."
|
|
617 |
|
|
618 |
|work|
|
|
619 |
|
|
620 |
%{ /* NOREGISTER - work may not be placed into a register here */
|
|
621 |
__nonTenuringScavenge(__context);
|
|
622 |
/*
|
|
623 |
* allInstancesDo needs a temporary to hold newSpace objects
|
|
624 |
*/
|
|
625 |
if (__allInstancesOfDo(&aClass, &aBlock, &work COMMA_CON) < 0) {
|
159
|
626 |
RETURN (false);
|
85
|
627 |
}
|
|
628 |
%}.
|
|
629 |
^ true
|
2
|
630 |
!
|
|
631 |
|
|
632 |
allOldObjectsDo:aBlock
|
|
633 |
"evaluate the argument, aBlock for all old objects in the system.
|
|
634 |
For debugging and tests only - do not use"
|
|
635 |
%{
|
369
|
636 |
if (__allInstancesOfDo((OBJ *)0, &aBlock, (OBJ *)0 COMMA_CON) < 0) {
|
159
|
637 |
RETURN (false);
|
85
|
638 |
}
|
|
639 |
%}.
|
|
640 |
^ true
|
1
|
641 |
! !
|
|
642 |
|
229
|
643 |
!ObjectMemory class methodsFor:'interrupt handler access'!
|
2
|
644 |
|
|
645 |
internalErrorHandler
|
13
|
646 |
"return the handler for ST/X internal errors.
|
|
647 |
An internal error is reported for example when a methods
|
|
648 |
bytecode is not a ByteArray, the selector table is not an Array
|
93
|
649 |
etc.
|
|
650 |
Those should not occur in normal circumstances."
|
13
|
651 |
|
2
|
652 |
^ InternalErrorHandler
|
|
653 |
!
|
|
654 |
|
|
655 |
userInterruptHandler
|
13
|
656 |
"return the handler for CNTL-C interrupt handling"
|
|
657 |
|
2
|
658 |
^ UserInterruptHandler
|
|
659 |
!
|
|
660 |
|
|
661 |
userInterruptHandler:aHandler
|
13
|
662 |
"set the handler for CNTL-C interrupt handling"
|
|
663 |
|
2
|
664 |
UserInterruptHandler := aHandler
|
|
665 |
!
|
|
666 |
|
|
667 |
timerInterruptHandler
|
13
|
668 |
"return the handler for timer interrupts"
|
|
669 |
|
2
|
670 |
^ TimerInterruptHandler
|
|
671 |
!
|
|
672 |
|
10
|
673 |
timerInterruptHandler:aHandler
|
13
|
674 |
"set the handler for timer interrupts"
|
|
675 |
|
10
|
676 |
TimerInterruptHandler := aHandler
|
|
677 |
!
|
|
678 |
|
2
|
679 |
spyInterruptHandler
|
13
|
680 |
"return the handler for spy-timer interrupts"
|
|
681 |
|
2
|
682 |
^ SpyInterruptHandler
|
|
683 |
!
|
|
684 |
|
|
685 |
spyInterruptHandler:aHandler
|
13
|
686 |
"set the handler for spy-timer interrupts"
|
|
687 |
|
2
|
688 |
SpyInterruptHandler := aHandler
|
|
689 |
!
|
|
690 |
|
|
691 |
stepInterruptHandler
|
13
|
692 |
"return the handler for single step interrupts"
|
|
693 |
|
2
|
694 |
^ StepInterruptHandler
|
|
695 |
!
|
|
696 |
|
|
697 |
stepInterruptHandler:aHandler
|
13
|
698 |
"set the handler for single step interrupts"
|
|
699 |
|
2
|
700 |
StepInterruptHandler := aHandler
|
|
701 |
!
|
|
702 |
|
|
703 |
exceptionInterruptHandler
|
13
|
704 |
"return the handler for floating point exception interrupts"
|
|
705 |
|
2
|
706 |
^ ExceptionInterruptHandler
|
|
707 |
!
|
|
708 |
|
|
709 |
errorInterruptHandler
|
13
|
710 |
"return the handler for display error interrupts"
|
|
711 |
|
2
|
712 |
^ ErrorInterruptHandler
|
|
713 |
!
|
|
714 |
|
|
715 |
errorInterruptHandler:aHandler
|
13
|
716 |
"set the handler for display error interrupts"
|
|
717 |
|
2
|
718 |
ErrorInterruptHandler := aHandler
|
|
719 |
!
|
|
720 |
|
345
|
721 |
registeredErrorInterruptHandlers
|
|
722 |
"return registered handlers"
|
|
723 |
|
|
724 |
^ RegisteredErrorInterruptHandlers
|
|
725 |
!
|
|
726 |
|
|
727 |
registerErrorInterruptHandler:aHandler forID:errorIDSymbol
|
|
728 |
"register a handler"
|
|
729 |
|
|
730 |
RegisteredErrorInterruptHandlers isNil ifTrue:[
|
|
731 |
RegisteredErrorInterruptHandlers := IdentityDictionary new
|
|
732 |
].
|
|
733 |
RegisteredErrorInterruptHandlers at:errorIDSymbol put:aHandler
|
|
734 |
!
|
|
735 |
|
13
|
736 |
signalInterruptHandler
|
|
737 |
"return the handler for UNIX-signal interrupts"
|
2
|
738 |
|
|
739 |
^ SignalInterruptHandler
|
|
740 |
!
|
|
741 |
|
13
|
742 |
signalInterruptHandler:aHandler
|
|
743 |
"set the handler for UNIX-signal interrupts"
|
|
744 |
|
|
745 |
SignalInterruptHandler := aHandler
|
|
746 |
!
|
|
747 |
|
2
|
748 |
childSignalInterruptHandler
|
13
|
749 |
"return the handler for UNIX-death-of-a-childprocess-signal interrupts"
|
|
750 |
|
2
|
751 |
^ ChildSignalInterruptHandler
|
|
752 |
!
|
|
753 |
|
|
754 |
disposeInterruptHandler
|
13
|
755 |
"return the handler for object disposal interrupts"
|
|
756 |
|
2
|
757 |
^ DisposeInterruptHandler
|
|
758 |
!
|
|
759 |
|
|
760 |
disposeInterruptHandler:aHandler
|
13
|
761 |
"set the handler for object disposal interrupts"
|
|
762 |
|
2
|
763 |
DisposeInterruptHandler := aHandler
|
|
764 |
!
|
|
765 |
|
|
766 |
recursionInterruptHandler
|
13
|
767 |
"return the handler for recursion/stack overflow interrupts"
|
|
768 |
|
2
|
769 |
^ RecursionInterruptHandler
|
|
770 |
!
|
|
771 |
|
13
|
772 |
recursionInterruptHandler:aHandler
|
|
773 |
"set the handler for recursion/stack overflow interrupts"
|
|
774 |
|
|
775 |
RecursionInterruptHandler := aHandler
|
|
776 |
!
|
|
777 |
|
2
|
778 |
ioInterruptHandler
|
13
|
779 |
"return the handler for I/O available signal interrupts (SIGIO/SIGPOLL)"
|
|
780 |
|
2
|
781 |
^ IOInterruptHandler
|
|
782 |
!
|
|
783 |
|
|
784 |
ioInterruptHandler:aHandler
|
13
|
785 |
"set the handler for I/O available signal interrupts (SIGIO/SIGPOLL)"
|
|
786 |
|
2
|
787 |
IOInterruptHandler := aHandler
|
85
|
788 |
!
|
|
789 |
|
|
790 |
customInterruptHandler
|
|
791 |
"return the handler for custom interrupts"
|
|
792 |
|
|
793 |
^ CustomInterruptHandler
|
|
794 |
!
|
|
795 |
|
|
796 |
customInterruptHandler:aHandler
|
|
797 |
"set the handler for custom interrupts"
|
|
798 |
|
|
799 |
CustomInterruptHandler := aHandler
|
2
|
800 |
! !
|
|
801 |
|
1
|
802 |
!ObjectMemory class methodsFor:'queries'!
|
|
803 |
|
13
|
804 |
newSpaceSize
|
|
805 |
"return the total size of the new space - this is usually fix"
|
|
806 |
|
|
807 |
%{ /* NOCONTEXT */
|
133
|
808 |
extern unsigned __newSpaceSize();
|
|
809 |
|
13
|
810 |
RETURN ( _MKSMALLINT(__newSpaceSize()) );
|
|
811 |
%}
|
93
|
812 |
"
|
|
813 |
ObjectMemory newSpaceSize
|
|
814 |
"
|
13
|
815 |
!
|
|
816 |
|
|
817 |
oldSpaceSize
|
|
818 |
"return the total size of the old space. - may grow slowly"
|
|
819 |
|
|
820 |
%{ /* NOCONTEXT */
|
133
|
821 |
extern unsigned __oldSpaceSize();
|
|
822 |
|
13
|
823 |
RETURN ( _MKSMALLINT(__oldSpaceSize()) );
|
|
824 |
%}
|
93
|
825 |
"
|
|
826 |
ObjectMemory oldSpaceSize
|
|
827 |
"
|
13
|
828 |
!
|
|
829 |
|
325
|
830 |
symSpaceSize
|
|
831 |
"return the total size of the sym space."
|
|
832 |
|
|
833 |
%{ /* NOCONTEXT */
|
|
834 |
extern unsigned __symSpaceSize();
|
|
835 |
|
|
836 |
RETURN ( _MKSMALLINT(__symSpaceSize()) );
|
|
837 |
%}
|
|
838 |
"
|
|
839 |
ObjectMemory symSpaceSize
|
|
840 |
"
|
|
841 |
!
|
|
842 |
|
216
|
843 |
fixSpaceSize
|
|
844 |
"return the total size of the fix space."
|
|
845 |
|
|
846 |
%{ /* NOCONTEXT */
|
|
847 |
extern unsigned __fixSpaceSize();
|
|
848 |
|
|
849 |
RETURN ( _MKSMALLINT(__fixSpaceSize()) );
|
|
850 |
%}
|
|
851 |
"
|
|
852 |
ObjectMemory fixSpaceSize
|
|
853 |
"
|
|
854 |
!
|
|
855 |
|
1
|
856 |
newSpaceUsed
|
10
|
857 |
"return the number of bytes allocated for new objects.
|
|
858 |
The returned value is usually obsolete as soon as you do
|
13
|
859 |
something with it ..."
|
1
|
860 |
|
|
861 |
%{ /* NOCONTEXT */
|
133
|
862 |
extern unsigned __newSpaceUsed();
|
|
863 |
|
1
|
864 |
RETURN ( _MKSMALLINT(__newSpaceUsed()) );
|
|
865 |
%}
|
93
|
866 |
"
|
202
|
867 |
ObjectMemory newSpaceUsed
|
93
|
868 |
"
|
1
|
869 |
!
|
|
870 |
|
|
871 |
oldSpaceUsed
|
10
|
872 |
"return the number of bytes allocated for old objects.
|
|
873 |
(This includes the free lists)"
|
1
|
874 |
|
|
875 |
%{ /* NOCONTEXT */
|
133
|
876 |
extern unsigned __oldSpaceUsed();
|
|
877 |
|
1
|
878 |
RETURN ( _MKSMALLINT(__oldSpaceUsed()) );
|
|
879 |
%}
|
93
|
880 |
"
|
202
|
881 |
ObjectMemory oldSpaceUsed
|
93
|
882 |
"
|
1
|
883 |
!
|
|
884 |
|
325
|
885 |
symSpaceUsed
|
|
886 |
"return the number of bytes allocated for old objects in sym space."
|
|
887 |
|
|
888 |
%{ /* NOCONTEXT */
|
|
889 |
extern unsigned __symSpaceUsed();
|
|
890 |
|
|
891 |
RETURN ( _MKSMALLINT(__symSpaceUsed()) );
|
|
892 |
%}
|
|
893 |
"
|
|
894 |
ObjectMemory symSpaceUsed
|
|
895 |
"
|
|
896 |
!
|
|
897 |
|
216
|
898 |
fixSpaceUsed
|
|
899 |
"return the number of bytes allocated for old objects in fix space."
|
|
900 |
|
|
901 |
%{ /* NOCONTEXT */
|
|
902 |
extern unsigned __fixSpaceUsed();
|
|
903 |
|
|
904 |
RETURN ( _MKSMALLINT(__fixSpaceUsed()) );
|
|
905 |
%}
|
|
906 |
"
|
|
907 |
ObjectMemory fixSpaceUsed
|
|
908 |
"
|
|
909 |
!
|
|
910 |
|
270
|
911 |
freeSpace
|
|
912 |
"return the number of bytes in the compact free area.
|
|
913 |
(oldSpaceUsed + freeSpaceSize = oldSpaceSize)"
|
|
914 |
|
|
915 |
%{ /* NOCONTEXT */
|
|
916 |
extern unsigned __oldSpaceSize(), __oldSpaceUsed();
|
|
917 |
|
|
918 |
RETURN ( _MKSMALLINT(__oldSpaceSize() - __oldSpaceUsed()) );
|
|
919 |
%}
|
|
920 |
"
|
|
921 |
ObjectMemory freeSpace
|
|
922 |
"
|
|
923 |
!
|
|
924 |
|
133
|
925 |
freeListSpace
|
10
|
926 |
"return the number of bytes in the free lists.
|
|
927 |
(which is included in oldSpaceUsed)"
|
|
928 |
|
|
929 |
%{ /* NOCONTEXT */
|
133
|
930 |
extern unsigned __freeListSpace();
|
|
931 |
|
|
932 |
RETURN ( _MKSMALLINT(__freeListSpace()) );
|
10
|
933 |
%}
|
93
|
934 |
"
|
133
|
935 |
ObjectMemory freeListSpace
|
93
|
936 |
"
|
10
|
937 |
!
|
|
938 |
|
1
|
939 |
bytesUsed
|
|
940 |
"return the number of bytes allocated for objects -
|
178
|
941 |
this number is not exact, since some objects may already be dead
|
|
942 |
(i.e. not yet reclaimed by the garbage collector).
|
|
943 |
If you need the exact number, you have to loop over all
|
|
944 |
objects and ask for the bytesize using ObjectMemory>>sizeOf:."
|
1
|
945 |
|
|
946 |
%{ /* NOCONTEXT */
|
133
|
947 |
extern unsigned __oldSpaceUsed(), __newSpaceUsed(), __freeListSpace();
|
|
948 |
|
|
949 |
RETURN ( _MKSMALLINT(__oldSpaceUsed() + __newSpaceUsed() - __freeListSpace()) );
|
1
|
950 |
%}
|
93
|
951 |
"
|
202
|
952 |
ObjectMemory bytesUsed
|
93
|
953 |
"
|
1
|
954 |
!
|
|
955 |
|
2
|
956 |
oldSpaceAllocatedSinceLastGC
|
|
957 |
"return the number of bytes allocated for old objects since the
|
178
|
958 |
last oldspace garbage collect occured. This information is used
|
|
959 |
by ProcessorScheduler to decide when to start the incremental
|
|
960 |
background GC."
|
2
|
961 |
|
|
962 |
%{ /* NOCONTEXT */
|
133
|
963 |
extern unsigned __oldSpaceAllocatedSinceLastGC();
|
|
964 |
|
2
|
965 |
RETURN ( _MKSMALLINT(__oldSpaceAllocatedSinceLastGC()) );
|
|
966 |
%}
|
93
|
967 |
"
|
202
|
968 |
ObjectMemory oldSpaceAllocatedSinceLastGC
|
93
|
969 |
"
|
2
|
970 |
!
|
|
971 |
|
178
|
972 |
tenureAge
|
|
973 |
"return the current tenure age - thats the number of times
|
|
974 |
an object has to survive scavenges to be moved into oldSpace.
|
202
|
975 |
For statistic/debugging only - this method may vanish"
|
178
|
976 |
|
|
977 |
%{ /* NOCONTEXT */
|
|
978 |
extern unsigned __tenureAge();
|
|
979 |
|
|
980 |
RETURN ( _MKSMALLINT(__tenureAge()) );
|
|
981 |
%}
|
|
982 |
!
|
|
983 |
|
362
|
984 |
lastScavengeReclamation
|
194
|
985 |
"returns the number of bytes replacimed by the last scavenge.
|
|
986 |
For statistic only - this may vanish."
|
|
987 |
|
|
988 |
%{ /* NOCONTEXT */
|
|
989 |
extern int __newSpaceReclaimed();
|
|
990 |
|
|
991 |
RETURN ( _MKSMALLINT(__newSpaceReclaimed()) );
|
|
992 |
%}
|
202
|
993 |
"percentage of reclaimed objects is returned by:
|
|
994 |
|
362
|
995 |
((ObjectMemory lastScavengeReclamation)
|
202
|
996 |
/ (ObjectMemory newSpaceSize)) * 100.0
|
194
|
997 |
"
|
|
998 |
!
|
|
999 |
|
362
|
1000 |
resetMinScavengeReclamation
|
|
1001 |
"resets the number of bytes replacimed by the least effective scavenge.
|
|
1002 |
For statistic only - this may vanish."
|
|
1003 |
|
|
1004 |
%{ /* NOCONTEXT */
|
|
1005 |
extern int __resetNewSpaceReclaimedMin();
|
|
1006 |
|
|
1007 |
__resetNewSpaceReclaimedMin();
|
|
1008 |
%}.
|
|
1009 |
^ self
|
|
1010 |
"
|
|
1011 |
ObjectMemory resetMinScavengeReclamation.
|
|
1012 |
ObjectMemory minScavengeReclamation
|
|
1013 |
"
|
|
1014 |
!
|
|
1015 |
|
|
1016 |
minScavengeReclamation
|
|
1017 |
"returns the number of bytes replacimed by the least effective scavenge.
|
|
1018 |
For statistic only - this may vanish."
|
|
1019 |
|
|
1020 |
%{ /* NOCONTEXT */
|
|
1021 |
extern int __newSpaceReclaimedMin();
|
|
1022 |
|
|
1023 |
RETURN ( _MKSMALLINT(__newSpaceReclaimedMin()) );
|
|
1024 |
%}
|
|
1025 |
"
|
|
1026 |
ObjectMemory minScavengeReclamation
|
|
1027 |
"
|
|
1028 |
!
|
|
1029 |
|
178
|
1030 |
runsSingleOldSpace
|
|
1031 |
"return true, if the system runs in a single oldSpace or
|
326
|
1032 |
false if not.
|
|
1033 |
The memory system will always drop the second semispace when
|
|
1034 |
running out of virtual memory, or the baker-limit is reached.
|
202
|
1035 |
OBSOLETE:
|
|
1036 |
the system may now decide at any time to switch between
|
|
1037 |
single and double-space algorithms, depending on the overall memory
|
|
1038 |
size. You will now almost always get false as result, since the
|
326
|
1039 |
second semispace is only allocated when needed, and released
|
|
1040 |
immediately afterwards.
|
202
|
1041 |
"
|
178
|
1042 |
|
|
1043 |
%{ /* NOCONTEXT */
|
357
|
1044 |
extern int __runsSingleOldSpace();
|
|
1045 |
|
|
1046 |
RETURN ( (__runsSingleOldSpace() ? true : false) );
|
178
|
1047 |
%}
|
202
|
1048 |
"
|
|
1049 |
ObjectMemory runsSingleOldSpace
|
|
1050 |
"
|
178
|
1051 |
!
|
|
1052 |
|
|
1053 |
incrementalGCPhase
|
|
1054 |
"returns the internal state of the incremental GC.
|
|
1055 |
The meaning of those numbers is a secret :-).
|
326
|
1056 |
(for the curious: (currently)
|
|
1057 |
2 is idle, 3..11 are various mark phases,
|
|
1058 |
12 is the sweep phase. 0 and 1 are cleanup phases when the
|
|
1059 |
incr. GC gets interrupted by a full GC).
|
356
|
1060 |
Do not depend on the values - there may be additional phases in
|
|
1061 |
future versions (incremental compact ;-).
|
326
|
1062 |
This is for debugging and monitoring only - and may change or vanish"
|
178
|
1063 |
|
|
1064 |
%{ /* NOCONTEXT */
|
|
1065 |
extern int __incrGCphase();
|
|
1066 |
|
|
1067 |
RETURN (_MKSMALLINT(__incrGCphase()));
|
|
1068 |
%}
|
|
1069 |
!
|
|
1070 |
|
270
|
1071 |
scavengeCount
|
|
1072 |
"return the number of scavenges that occurred since startup"
|
|
1073 |
|
|
1074 |
%{ /* NOCONTEXT */
|
|
1075 |
extern int __scavengeCount();
|
|
1076 |
|
|
1077 |
RETURN (_MKSMALLINT(__scavengeCount()));
|
|
1078 |
%}
|
|
1079 |
"
|
|
1080 |
ObjectMemory scavengeCount
|
|
1081 |
"
|
|
1082 |
!
|
|
1083 |
|
|
1084 |
markAndSweepCount
|
|
1085 |
"return the number of mark&sweep collects that occurred since startup"
|
|
1086 |
|
|
1087 |
%{ /* NOCONTEXT */
|
|
1088 |
extern int __markAndSweepCount();
|
|
1089 |
|
|
1090 |
RETURN (_MKSMALLINT(__markAndSweepCount()));
|
|
1091 |
%}
|
|
1092 |
"
|
|
1093 |
ObjectMemory markAndSweepCount
|
|
1094 |
"
|
|
1095 |
!
|
|
1096 |
|
|
1097 |
garbageCollectCount
|
|
1098 |
"return the number of compressing collects that occurred since startup"
|
|
1099 |
|
|
1100 |
%{ /* NOCONTEXT */
|
|
1101 |
extern int __garbageCollectCount();
|
|
1102 |
|
|
1103 |
RETURN (_MKSMALLINT(__garbageCollectCount()));
|
|
1104 |
%}
|
|
1105 |
"
|
|
1106 |
ObjectMemory garbageCollectCount
|
|
1107 |
"
|
|
1108 |
!
|
|
1109 |
|
362
|
1110 |
rememberedSetSize
|
369
|
1111 |
"return the number of old objects referencing new ones.
|
|
1112 |
This is a VM debugging interface and may vanish without notice."
|
362
|
1113 |
|
|
1114 |
%{ /* NOCONTEXT */
|
|
1115 |
extern int __rememberedSetSize();
|
|
1116 |
|
|
1117 |
RETURN (_MKSMALLINT(__rememberedSetSize()));
|
|
1118 |
%}
|
|
1119 |
"
|
|
1120 |
ObjectMemory rememberedSetSize
|
|
1121 |
"
|
|
1122 |
!
|
|
1123 |
|
369
|
1124 |
lifoRememberedSetSize
|
|
1125 |
"return the size of the lifoRemSet.
|
|
1126 |
This is a VM debugging interface and may vanish without notice."
|
|
1127 |
|
|
1128 |
%{ /* NOCONTEXT */
|
|
1129 |
extern int __lifoRememberedSetSize();
|
|
1130 |
|
|
1131 |
RETURN (_MKSMALLINT(__lifoRememberedSetSize()));
|
|
1132 |
%}
|
|
1133 |
"
|
|
1134 |
ObjectMemory lifoRememberedSetSize
|
|
1135 |
"
|
|
1136 |
!
|
|
1137 |
|
|
1138 |
lifoRememberedSet
|
|
1139 |
"return the lifoRemSet.
|
|
1140 |
This is pure VM debugging and will vanish without notice."
|
|
1141 |
|
|
1142 |
%{ /* NOCONTEXT */
|
|
1143 |
extern OBJ __lifoRememberedSet();
|
|
1144 |
|
|
1145 |
RETURN ( __lifoRememberedSet() );
|
|
1146 |
%}
|
|
1147 |
"
|
|
1148 |
ObjectMemory lifoRememberedSet
|
|
1149 |
"
|
|
1150 |
!
|
|
1151 |
|
|
1152 |
numberOfWeakObjects
|
|
1153 |
"return the number of weak objects in the system"
|
|
1154 |
|
|
1155 |
%{ /* NOCONTEXT */
|
|
1156 |
extern int __weakListSize();
|
|
1157 |
|
|
1158 |
RETURN ( __MKSMALLINT(__weakListSize()) );
|
|
1159 |
%}
|
|
1160 |
"
|
|
1161 |
ObjectMemory numberOfWeakObjects
|
|
1162 |
"
|
|
1163 |
!
|
|
1164 |
|
1
|
1165 |
numberOfObjects
|
13
|
1166 |
"return the number of objects in the system."
|
1
|
1167 |
|
326
|
1168 |
|tally "{ Class: SmallInteger }"|
|
1
|
1169 |
|
|
1170 |
tally := 0.
|
|
1171 |
self allObjectsDo:[:obj | tally := tally + 1].
|
|
1172 |
^ tally
|
|
1173 |
|
93
|
1174 |
"
|
202
|
1175 |
ObjectMemory numberOfObjects
|
93
|
1176 |
"
|
1
|
1177 |
!
|
|
1178 |
|
|
1179 |
printReferences:anObject
|
178
|
1180 |
"for debugging: print referents to anObject.
|
202
|
1181 |
WARNING:
|
|
1182 |
this method will vanish;
|
|
1183 |
use ObjectMemory>>whoReferences: or anObject>>allOwners."
|
1
|
1184 |
|
|
1185 |
%{
|
329
|
1186 |
__printRefChain(__context, anObject);
|
1
|
1187 |
%}
|
|
1188 |
!
|
|
1189 |
|
202
|
1190 |
collectObjectsWhich:aBlock
|
|
1191 |
"helper for the whoReferences queries. Returns a collection
|
|
1192 |
of objects for which aBlock returns true."
|
1
|
1193 |
|
|
1194 |
|aCollection|
|
|
1195 |
|
|
1196 |
aCollection := IdentitySet new.
|
|
1197 |
self allObjectsDo:[:o |
|
202
|
1198 |
(aBlock value:o) ifTrue:[
|
159
|
1199 |
aCollection add:o
|
|
1200 |
]
|
1
|
1201 |
].
|
|
1202 |
(aCollection size == 0) ifTrue:[
|
159
|
1203 |
"actually this cannot happen - there is always one"
|
|
1204 |
^ nil
|
1
|
1205 |
].
|
|
1206 |
^ aCollection
|
13
|
1207 |
!
|
|
1208 |
|
202
|
1209 |
whoReferences:anObject
|
|
1210 |
"return a collection of objects referencing the argument, anObject"
|
|
1211 |
|
|
1212 |
^ self collectObjectsWhich:[:o | o references:anObject]
|
|
1213 |
|
|
1214 |
"
|
|
1215 |
(ObjectMemory whoReferences:Transcript) printNL
|
|
1216 |
"
|
|
1217 |
!
|
|
1218 |
|
|
1219 |
whoReferencesInstancesOf:aClass
|
|
1220 |
"return a collection of objects refering to instances
|
|
1221 |
of the argument, aClass"
|
|
1222 |
|
|
1223 |
^ self collectObjectsWhich:[:o | o referencesInstanceOf:aClass]
|
|
1224 |
|
|
1225 |
"
|
|
1226 |
(ObjectMemory whoReferencesInstancesOf:SystemBrowser) printNL
|
|
1227 |
"
|
|
1228 |
!
|
|
1229 |
|
|
1230 |
whoReferencesDerivedInstancesOf:aClass
|
|
1231 |
"return a collection of objects refering to instances
|
|
1232 |
of the argument, aClass or a subclass of it."
|
|
1233 |
|
|
1234 |
^ self collectObjectsWhich:[:o | o referencesDerivedInstanceOf:aClass]
|
|
1235 |
|
|
1236 |
"
|
|
1237 |
(ObjectMemory whoReferencesDerivedInstancesOf:View) printNL
|
|
1238 |
"
|
|
1239 |
!
|
|
1240 |
|
13
|
1241 |
addressOf:anObject
|
|
1242 |
"return the core address of anObject as an integer
|
|
1243 |
- since objects may move around, the returned value is invalid after the
|
|
1244 |
next scavenge/collect.
|
|
1245 |
Use only for debugging."
|
|
1246 |
|
|
1247 |
%{ /* NOCONTEXT */
|
|
1248 |
|
329
|
1249 |
if (! __isNonNilObject(anObject)) {
|
159
|
1250 |
RETURN ( nil );
|
13
|
1251 |
}
|
326
|
1252 |
if (((int)anObject >= _MIN_INT) && ((int)anObject <= _MAX_INT)) {
|
|
1253 |
RETURN ( _MKSMALLINT((int)anObject) );
|
|
1254 |
}
|
|
1255 |
RETURN ( _MKLARGEINT((int)anObject) );
|
13
|
1256 |
%}
|
|
1257 |
"
|
|
1258 |
|p|
|
|
1259 |
p := Point new.
|
370
|
1260 |
((ObjectMemory addressOf:p) printStringRadix:16) printNL.
|
13
|
1261 |
ObjectMemory scavenge.
|
370
|
1262 |
((ObjectMemory addressOf:p) printStringRadix:16) printNL.
|
13
|
1263 |
"
|
|
1264 |
!
|
|
1265 |
|
159
|
1266 |
objectAt:anAddress
|
|
1267 |
"return whatever anAddress points to as object.
|
202
|
1268 |
BIG BIG DANGER ALERT:
|
326
|
1269 |
this method is only to be used for debugging ST/X itself
|
|
1270 |
- you can easily (and badly) crash the system.
|
|
1271 |
This method may be removed from the final shipping version"
|
159
|
1272 |
|
|
1273 |
|low high|
|
|
1274 |
|
|
1275 |
low := anAddress bitAnd:16rFFFF.
|
|
1276 |
high := (anAddress bitShift:16) bitAnd:16rFFFF.
|
|
1277 |
%{
|
253
|
1278 |
if (__bothSmallInteger(low, high)) {
|
159
|
1279 |
RETURN ((OBJ)((_intVal(high) << 16) | _intVal(low)));
|
|
1280 |
}
|
|
1281 |
%}
|
|
1282 |
!
|
|
1283 |
|
13
|
1284 |
sizeOf:anObject
|
|
1285 |
"return the size of anObject in bytes.
|
326
|
1286 |
(this is not the same as 'anObject size').
|
13
|
1287 |
Use only for debugging/memory monitoring."
|
|
1288 |
|
|
1289 |
%{ /* NOCONTEXT */
|
|
1290 |
|
329
|
1291 |
RETURN ( __isNonNilObject(anObject) ? _MKSMALLINT(__qSize(anObject)) : _MKSMALLINT(0) )
|
13
|
1292 |
%}
|
|
1293 |
"
|
|
1294 |
|hist big nw|
|
|
1295 |
|
|
1296 |
hist := Array new:100 withAll:0.
|
|
1297 |
big := 0.
|
|
1298 |
ObjectMemory allObjectsDo:[:o |
|
159
|
1299 |
nw := (ObjectMemory sizeOf:o) // 4 + 1.
|
|
1300 |
nw > 100 ifTrue:[
|
|
1301 |
big := big + 1
|
|
1302 |
] ifFalse:[
|
|
1303 |
hist at:nw put:(hist at:nw) + 1
|
|
1304 |
].
|
13
|
1305 |
].
|
77
|
1306 |
hist printNL.
|
|
1307 |
big printNL
|
13
|
1308 |
"
|
|
1309 |
!
|
|
1310 |
|
|
1311 |
spaceOf:anObject
|
|
1312 |
"return the memory space, in which anObject is.
|
326
|
1313 |
- since objects may move between spaces,
|
|
1314 |
the returned value may be invalid after the next scavenge/collect.
|
202
|
1315 |
For debugging only; Dont use this method; it may vanish."
|
13
|
1316 |
|
|
1317 |
%{ /* NOCONTEXT */
|
|
1318 |
|
329
|
1319 |
if (! __isNonNilObject(anObject)) {
|
159
|
1320 |
RETURN ( nil );
|
13
|
1321 |
}
|
325
|
1322 |
RETURN ( _MKSMALLINT( __qSpace(anObject) ) );
|
13
|
1323 |
%}
|
159
|
1324 |
!
|
|
1325 |
|
|
1326 |
flagsOf:anObject
|
202
|
1327 |
"For debugging only; Dont use this method; it may vanish."
|
|
1328 |
|
159
|
1329 |
%{ /* NOCONTEXT */
|
|
1330 |
|
329
|
1331 |
if (! __isNonNilObject(anObject)) {
|
159
|
1332 |
RETURN ( nil );
|
|
1333 |
}
|
|
1334 |
RETURN ( _MKSMALLINT( anObject->o_flags ) );
|
|
1335 |
%}
|
13
|
1336 |
"
|
202
|
1337 |
F_ISREMEMBERED 1 /* a new-space thing being refd by some oldSpace thing */
|
|
1338 |
F_ISFORWARDED 2 /* a forwarded object (you will never see this here) */
|
159
|
1339 |
F_DEREFERENCED 4 /* a collection after grow (not currently used) */
|
|
1340 |
F_ISONLIFOLIST 8 /* a non-lifo-context-referencing-obj already on list */
|
|
1341 |
F_MARK 16 /* mark bit for background collector */
|
77
|
1342 |
"
|
326
|
1343 |
|
|
1344 |
"
|
|
1345 |
|arr|
|
|
1346 |
|
|
1347 |
arr := Array new.
|
|
1348 |
arr at:1 put:([thisContext] value).
|
|
1349 |
(ObjectMemory flagsOf:anObject) printNL
|
|
1350 |
"
|
77
|
1351 |
!
|
|
1352 |
|
|
1353 |
ageOf:anObject
|
|
1354 |
"return the number of scavenges, an object has survived
|
326
|
1355 |
in new space.
|
|
1356 |
For old objects and living contexts, the returned number is invalid.
|
202
|
1357 |
For debugging only; Dont use this method; it may vanish."
|
77
|
1358 |
|
|
1359 |
%{ /* NOCONTEXT */
|
|
1360 |
|
329
|
1361 |
if (! __isNonNilObject(anObject)) {
|
159
|
1362 |
RETURN ( 0 );
|
77
|
1363 |
}
|
|
1364 |
RETURN ( _MKSMALLINT( _GET_AGE(anObject) ) );
|
|
1365 |
%}
|
|
1366 |
"
|
|
1367 |
|p|
|
|
1368 |
p := Point new.
|
|
1369 |
(ObjectMemory ageOf:p) printNL.
|
|
1370 |
ObjectMemory tenuringScavenge.
|
|
1371 |
(ObjectMemory spaceOf:p) printNL.
|
|
1372 |
ObjectMemory tenuringScavenge.
|
|
1373 |
(ObjectMemory spaceOf:p) printNL.
|
|
1374 |
ObjectMemory tenuringScavenge.
|
|
1375 |
(ObjectMemory spaceOf:p) printNL.
|
|
1376 |
ObjectMemory tenuringScavenge.
|
|
1377 |
(ObjectMemory spaceOf:p) printNL.
|
13
|
1378 |
"
|
324
|
1379 |
!
|
|
1380 |
|
|
1381 |
maximumIdentityHashValue
|
|
1382 |
"for ST-80 compatibility: return the maximum value
|
|
1383 |
a hashKey as returned by identityHash can get.
|
|
1384 |
Since ST/X uses direct pointers, a field in the objectHeader
|
370
|
1385 |
is used, which is currently 11 bits in size."
|
|
1386 |
|
|
1387 |
%{ /* NOCONTEXT */
|
|
1388 |
RETURN ( __MKSMALLINT( __MAX_HASH__ << __HASH_SHIFT__) );
|
|
1389 |
%}
|
|
1390 |
"
|
|
1391 |
ObjectMemory maximumIdentityHashValue
|
|
1392 |
"
|
1
|
1393 |
! !
|
|
1394 |
|
178
|
1395 |
!ObjectMemory class methodsFor:'garbage collection'!
|
1
|
1396 |
|
133
|
1397 |
scavenge
|
|
1398 |
"collect young objects, without aging (i.e. no tenure).
|
|
1399 |
Can be used to quickly get rid of shortly before allocated
|
|
1400 |
stuff. This is relatively fast (compared to oldspace collect).
|
|
1401 |
|
|
1402 |
An example where a non-tenuring scavenge makes sense is when
|
|
1403 |
allocating some OperatingSystem resource (a Color, File or View)
|
|
1404 |
and the OS runs out of resources. In this case, the scavenge may
|
|
1405 |
free some ST-objects and therefore (by signalling the WeakArrays
|
|
1406 |
or Registries) free the OS resources too.
|
|
1407 |
Of course, only recently allocated resources will be freed this
|
|
1408 |
way. If none was freed, a full collect will be needed."
|
|
1409 |
%{
|
326
|
1410 |
__nonTenuringScavenge(__context);
|
133
|
1411 |
%}
|
|
1412 |
|
|
1413 |
"
|
|
1414 |
ObjectMemory scavenge
|
|
1415 |
"
|
|
1416 |
!
|
|
1417 |
|
|
1418 |
tenuringScavenge
|
|
1419 |
"collect newspace stuff, with aging (i.e. objects old enough
|
|
1420 |
will be moved into the oldSpace).
|
|
1421 |
Use this for debugging and testing only - the system performs
|
|
1422 |
this automatically when the newspace fills up.
|
|
1423 |
This is relatively fast (compared to oldspace collect)"
|
|
1424 |
%{
|
326
|
1425 |
__scavenge(__context);
|
133
|
1426 |
%}
|
|
1427 |
|
|
1428 |
"
|
|
1429 |
ObjectMemory tenuringScavenge
|
|
1430 |
"
|
|
1431 |
!
|
|
1432 |
|
|
1433 |
tenure
|
|
1434 |
"force all living new stuff into old-space - effectively making
|
312
|
1435 |
all living young objects become old objects immediately.
|
133
|
1436 |
This is relatively fast (compared to oldspace collect).
|
|
1437 |
|
|
1438 |
This method should only be used in very special situations:
|
|
1439 |
for example, when building up some long-living data structure
|
|
1440 |
in a time critical application.
|
194
|
1441 |
To do so, you have to do a scavenge followed by a tenure after the
|
133
|
1442 |
objects are created. Be careful, to not reference any other chunk-
|
|
1443 |
data when calling for a tenure (this will lead to lots of garbage in
|
|
1444 |
the oldspace).
|
|
1445 |
In normal situations, explicit tenures are not needed."
|
|
1446 |
%{
|
326
|
1447 |
__tenure(__context);
|
133
|
1448 |
%}
|
|
1449 |
|
|
1450 |
"
|
|
1451 |
ObjectMemory tenure
|
|
1452 |
"
|
194
|
1453 |
"
|
|
1454 |
... build up long living objects ...
|
|
1455 |
ObjectMemory scavenge.
|
|
1456 |
ObjectMemory tenure
|
|
1457 |
... continue - objects created above are now in oldSpace ...
|
|
1458 |
"
|
133
|
1459 |
!
|
|
1460 |
|
1
|
1461 |
garbageCollect
|
178
|
1462 |
"search for and free garbage in the oldSpace (newSpace is cleaned automatically)
|
|
1463 |
performing a COMPRESSING garbage collect.
|
133
|
1464 |
This can take a long time - especially, if paging is involved
|
178
|
1465 |
(when no paging is involved, its faster than I thought :-).
|
202
|
1466 |
If no memory is available for the compress, or the system has been started with
|
|
1467 |
the -Msingle option, this does a non-COMPRESSING collect."
|
1
|
1468 |
%{
|
178
|
1469 |
if (! __garbageCollect(__context)) {
|
326
|
1470 |
__markAndSweep(__context);
|
178
|
1471 |
}
|
1
|
1472 |
%}
|
|
1473 |
|
93
|
1474 |
"
|
|
1475 |
ObjectMemory garbageCollect
|
|
1476 |
"
|
1
|
1477 |
!
|
|
1478 |
|
93
|
1479 |
reclaimSymbols
|
|
1480 |
"reclaim unused symbols;
|
159
|
1481 |
Unused symbols are (currently) not reclaimed automatically,
|
369
|
1482 |
but only upon request with this method.
|
|
1483 |
It takes some time to do this ... and it is NOT interruptable.
|
202
|
1484 |
Future versions may do this automatically, while garbage collecting."
|
93
|
1485 |
%{
|
|
1486 |
__reclaimSymbols(__context);
|
|
1487 |
%}
|
|
1488 |
"
|
|
1489 |
ObjectMemory reclaimSymbols
|
|
1490 |
"
|
|
1491 |
!
|
|
1492 |
|
1
|
1493 |
markAndSweep
|
133
|
1494 |
"mark/sweep garbage collector.
|
|
1495 |
perform a full mark&sweep collect.
|
369
|
1496 |
Warning: this may take some time and it is NOT interruptable.
|
|
1497 |
If you want to do a collect from a background process, or have
|
|
1498 |
other things to do, better use #incrementalGC which is interruptable."
|
1
|
1499 |
%{
|
326
|
1500 |
__markAndSweep(__context);
|
1
|
1501 |
%}
|
|
1502 |
|
93
|
1503 |
"
|
133
|
1504 |
ObjectMemory markAndSweep
|
|
1505 |
"
|
1
|
1506 |
!
|
|
1507 |
|
|
1508 |
gcStep
|
77
|
1509 |
"one incremental garbage collect step.
|
|
1510 |
Mark or sweep some small number of objects. This
|
85
|
1511 |
method will return after a reasonable (short) time.
|
133
|
1512 |
This is used by the ProcessorScheduler at idle times.
|
|
1513 |
Returns true, if an incremental GC cycle has finished."
|
1
|
1514 |
%{
|
133
|
1515 |
extern int __incrGCstep();
|
|
1516 |
|
|
1517 |
RETURN (__incrGCstep(__context) ? true : false);
|
1
|
1518 |
%}
|
|
1519 |
!
|
|
1520 |
|
133
|
1521 |
incrementalGC
|
|
1522 |
"perform one round of incremental GC steps.
|
202
|
1523 |
The overall effect of this method is the same as calling markAndSweep.
|
133
|
1524 |
However, #incrementalGC is interruptable while #markAndSweep
|
369
|
1525 |
is atomic and blocks for a while.
|
|
1526 |
Thus this method can be called from a low prio (background) process
|
|
1527 |
to collect without disturbing foreground processes too much.
|
|
1528 |
(however, if you have nothing else to do, its better to call for markAndSweep,
|
|
1529 |
since it is faster)
|
159
|
1530 |
For example, someone allocating huge amounts of memory could
|
|
1531 |
ask for the possibility of a quick allocation using
|
|
1532 |
#checkForFastNew: and try a #incrementalGC if not. In many
|
270
|
1533 |
cases, this can avoid a pause (in the higher prio processes) due to
|
|
1534 |
a blocking GC."
|
133
|
1535 |
|
369
|
1536 |
[self gcStep] whileFalse:[].
|
|
1537 |
self moreOldSpaceIfUseful
|
133
|
1538 |
|
|
1539 |
"
|
|
1540 |
ObjectMemory incrementalGC
|
356
|
1541 |
[ObjectMemory incrementalGC] forkAt:3
|
133
|
1542 |
"
|
194
|
1543 |
!
|
|
1544 |
|
270
|
1545 |
gcStepIfUseful
|
|
1546 |
"If either the IncrementalGCLimit or the FreeSpaceGCLimits have been
|
290
|
1547 |
reached, perform one incremental garbage collect step.
|
|
1548 |
Return true, if more gcSteps are required to finish the cycle,
|
|
1549 |
false if done with a gc round.
|
|
1550 |
If no limit has been reached yet, do nothing and return false.
|
312
|
1551 |
This is called by the ProcessorScheduler at idle times or by the
|
|
1552 |
backgroundCollector."
|
270
|
1553 |
|
310
|
1554 |
|done limit free amount|
|
270
|
1555 |
|
290
|
1556 |
limit := IncrementalGCLimit.
|
|
1557 |
(limit notNil and:[self oldSpaceAllocatedSinceLastGC > limit]) ifTrue:[
|
369
|
1558 |
done := ObjectMemory gcStep
|
|
1559 |
] ifFalse:[
|
|
1560 |
limit := FreeSpaceGCLimit.
|
|
1561 |
(limit notNil and:[(self freeSpace + self freeListSpace) < limit]) ifTrue:[
|
|
1562 |
done := ObjectMemory gcStep.
|
|
1563 |
done ifTrue:[
|
|
1564 |
self moreOldSpaceIfUseful
|
|
1565 |
].
|
|
1566 |
] ifFalse:[
|
|
1567 |
done := true
|
|
1568 |
]
|
290
|
1569 |
].
|
369
|
1570 |
^ done not
|
270
|
1571 |
!
|
|
1572 |
|
194
|
1573 |
verboseGarbageCollect
|
|
1574 |
"perform a compessing garbage collect and show some informational
|
|
1575 |
output on the Transcript"
|
|
1576 |
|
370
|
1577 |
|nBytesBefore nReclaimed value unit|
|
194
|
1578 |
|
|
1579 |
nBytesBefore := self oldSpaceUsed.
|
|
1580 |
self garbageCollect.
|
|
1581 |
nReclaimed := nBytesBefore - self oldSpaceUsed.
|
|
1582 |
nReclaimed > 0 ifTrue:[
|
|
1583 |
nReclaimed > 1024 ifTrue:[
|
|
1584 |
nReclaimed > (1024 * 1024) ifTrue:[
|
370
|
1585 |
value := nReclaimed // (1024 * 1024).
|
|
1586 |
unit := ' Mb.'
|
194
|
1587 |
] ifFalse:[
|
370
|
1588 |
value := nReclaimed // 1024.
|
|
1589 |
unit := ' Kb.'
|
194
|
1590 |
]
|
|
1591 |
] ifFalse:[
|
370
|
1592 |
value := nReclaimed.
|
|
1593 |
unit := ' bytes.'
|
|
1594 |
].
|
|
1595 |
Transcript show:'reclaimed '; show:value printString.
|
|
1596 |
Transcript showCr:unit
|
194
|
1597 |
]
|
|
1598 |
|
|
1599 |
"
|
|
1600 |
ObjectMemory verboseGarbageCollect
|
|
1601 |
"
|
207
|
1602 |
!
|
|
1603 |
|
|
1604 |
startBackgroundCollectorAt:aPriority
|
|
1605 |
"start a process doing incremental GC in the background.
|
|
1606 |
Use this, if you have suspendable background processes which
|
|
1607 |
run all the time, and therefore would prevent the idle-collector
|
|
1608 |
from running. See documentation in this class for more details."
|
|
1609 |
|
290
|
1610 |
|p|
|
|
1611 |
|
270
|
1612 |
"/
|
|
1613 |
"/ its not useful, to run it more than once
|
|
1614 |
"/
|
207
|
1615 |
BackgroundCollectProcess notNil ifTrue:[
|
|
1616 |
BackgroundCollectProcess priority:aPriority.
|
|
1617 |
^ self
|
|
1618 |
].
|
270
|
1619 |
|
290
|
1620 |
p :=
|
207
|
1621 |
[
|
290
|
1622 |
[
|
|
1623 |
[true] whileTrue:[
|
|
1624 |
self gcStepIfUseful ifTrue:[
|
|
1625 |
"
|
|
1626 |
perform a full cycle
|
|
1627 |
"
|
|
1628 |
self incrementalGC
|
|
1629 |
].
|
270
|
1630 |
"
|
290
|
1631 |
wait a bit
|
|
1632 |
"
|
|
1633 |
(Delay forSeconds:5) wait
|
|
1634 |
]
|
|
1635 |
] valueOnUnwindDo:[
|
|
1636 |
BackgroundCollectProcess := nil
|
211
|
1637 |
]
|
207
|
1638 |
] newProcess.
|
290
|
1639 |
p name:'background collector'.
|
|
1640 |
p priority:aPriority.
|
339
|
1641 |
p restartable:true.
|
290
|
1642 |
p resume.
|
|
1643 |
BackgroundCollectProcess := p
|
211
|
1644 |
|
|
1645 |
"
|
293
|
1646 |
the following lets the backgroundCollector run at prio 5
|
|
1647 |
whenever 100000 bytes have been allocated, OR freeSpace drops
|
|
1648 |
below 1meg. Having the system keep 1meg as reserve for peak allocation.
|
|
1649 |
|
|
1650 |
Doing this may reduce pauses due to inevitable collects when running
|
|
1651 |
out of freeSpace, if the collector can keep up with allocation rate.
|
|
1652 |
"
|
|
1653 |
|
|
1654 |
"
|
|
1655 |
ObjectMemory incrementalGCLimit:100000.
|
|
1656 |
ObjectMemory freeSpaceGCLimit:1000000.
|
211
|
1657 |
ObjectMemory startBackgroundCollectorAt:5
|
|
1658 |
"
|
207
|
1659 |
!
|
|
1660 |
|
|
1661 |
stopBackgroundCollector
|
|
1662 |
"stop the background collector"
|
|
1663 |
|
|
1664 |
BackgroundCollectProcess notNil ifTrue:[
|
|
1665 |
BackgroundCollectProcess terminate.
|
|
1666 |
BackgroundCollectProcess := nil
|
|
1667 |
]
|
293
|
1668 |
|
211
|
1669 |
"
|
|
1670 |
ObjectMemory stopBackgroundCollector
|
|
1671 |
"
|
362
|
1672 |
!
|
|
1673 |
|
|
1674 |
backgroundCollectorRunning
|
|
1675 |
"return true, if a backgroundCollector is running"
|
|
1676 |
|
|
1677 |
^ BackgroundCollectProcess notNil
|
|
1678 |
|
|
1679 |
"
|
|
1680 |
ObjectMemory backgroundCollectorRunning
|
|
1681 |
"
|
178
|
1682 |
! !
|
|
1683 |
|
|
1684 |
!ObjectMemory class methodsFor:'garbage collector control'!
|
133
|
1685 |
|
270
|
1686 |
freeSpaceGCLimit:aNumber
|
|
1687 |
"set the freeSpace limit for incremental GC activation.
|
|
1688 |
The system will start doing incremental background GC, once less than this number
|
310
|
1689 |
of bytes are available for allocation.
|
|
1690 |
The default is nil; setting it to nil will turn this trigger off."
|
270
|
1691 |
|
|
1692 |
FreeSpaceGCLimit := aNumber
|
|
1693 |
|
|
1694 |
"
|
310
|
1695 |
the following will start the incrementalGC (in the background)
|
|
1696 |
whenever the freeSpace drops below 1meg of free space
|
290
|
1697 |
"
|
|
1698 |
"
|
|
1699 |
ObjectMemory freeSpaceGCLimit:1000000.
|
|
1700 |
"
|
|
1701 |
|
|
1702 |
"
|
293
|
1703 |
turn it off (i.e. let the system hit the wall ...)
|
290
|
1704 |
"
|
|
1705 |
"
|
270
|
1706 |
ObjectMemory freeSpaceGCLimit:nil.
|
|
1707 |
"
|
|
1708 |
!
|
|
1709 |
|
310
|
1710 |
freeSpaceGCAmount:aNumber
|
|
1711 |
"set the amount to be allocated if, after an incrementalGC,
|
|
1712 |
not at least FreeSpaceGCLimit bytes are available for allocation.
|
|
1713 |
The amount should be greater than the limit, otherwise the incremental
|
|
1714 |
GC may try over and over to get the memory (actually waisting time)."
|
|
1715 |
|
|
1716 |
FreeSpaceGCAmount := aNumber
|
|
1717 |
|
|
1718 |
"
|
|
1719 |
the following will try to always keep at least 1meg of free space
|
|
1720 |
(in the background) and start to do so, whenever the freeSpace drops
|
|
1721 |
below 250k.
|
|
1722 |
"
|
|
1723 |
"
|
|
1724 |
ObjectMemory freeSpaceGCLimit:250000.
|
|
1725 |
ObjectMemory freeSpaceGCAmount:1000000.
|
|
1726 |
"
|
|
1727 |
|
|
1728 |
"
|
|
1729 |
turn it off (i.e. let the system compute an appropriate amount ...)
|
|
1730 |
"
|
|
1731 |
"
|
|
1732 |
ObjectMemory freeSpaceGCAmount:nil.
|
|
1733 |
"
|
|
1734 |
!
|
|
1735 |
|
270
|
1736 |
freeSpaceGCLimit
|
|
1737 |
"return the freeSpace limit for incremental GC activation.
|
|
1738 |
The system will start doing incremental background GC, once less than this number
|
|
1739 |
of bytes are available in the compact free space.
|
|
1740 |
The default is 100000; setting it to nil will turn this trigger off."
|
|
1741 |
|
|
1742 |
^ FreeSpaceGCLimit
|
|
1743 |
|
|
1744 |
"
|
|
1745 |
ObjectMemory freeSpaceGCLimit
|
|
1746 |
"
|
|
1747 |
!
|
|
1748 |
|
310
|
1749 |
freeSpaceGCAmount
|
|
1750 |
"return the amount to be allocated if, after an incrementalGC,
|
|
1751 |
not at least FreeSpaceGCLimit bytes are available for allocation.
|
|
1752 |
The default is nil, which lets the system compute an abbpropriate value"
|
|
1753 |
|
|
1754 |
^ FreeSpaceGCAmount
|
|
1755 |
|
|
1756 |
"
|
|
1757 |
ObjectMemory freeSpaceGCAmount
|
|
1758 |
"
|
|
1759 |
!
|
|
1760 |
|
2
|
1761 |
incrementalGCLimit:aNumber
|
270
|
1762 |
"set the allocatedSinceLastGC limit for incremental GC activation.
|
|
1763 |
The system will start doing incremental background GC, once more than this number
|
|
1764 |
of bytes have been allocated since the last GC.
|
|
1765 |
The default is 500000; setting it to nil will turn this trigger off."
|
2
|
1766 |
|
|
1767 |
IncrementalGCLimit := aNumber
|
|
1768 |
|
85
|
1769 |
"
|
213
|
1770 |
ObjectMemory incrementalGCLimit:500000. 'do incr. GC very seldom'
|
|
1771 |
ObjectMemory incrementalGCLimit:100000. 'medium'
|
|
1772 |
ObjectMemory incrementalGCLimit:10000. 'do incr. GC very often'
|
|
1773 |
ObjectMemory incrementalGCLimit:nil. 'never'
|
85
|
1774 |
"
|
2
|
1775 |
!
|
|
1776 |
|
13
|
1777 |
incrementalGCLimit
|
270
|
1778 |
"return the allocatedSinceLastGC limit for incremental GC activation.
|
|
1779 |
The system will start doing incremental background GC, once more than this number
|
|
1780 |
of bytes have been allocated since the last GC.
|
|
1781 |
The default is 500000; setting it to nil will turn this trigger off."
|
13
|
1782 |
|
|
1783 |
^ IncrementalGCLimit
|
|
1784 |
|
85
|
1785 |
"
|
|
1786 |
ObjectMemory incrementalGCLimit
|
|
1787 |
"
|
13
|
1788 |
!
|
|
1789 |
|
369
|
1790 |
moreOldSpaceIfUseful
|
|
1791 |
"to be called after an incremental GC cycle;
|
|
1792 |
if freeSpace is still below limit, allocate more oldSpace"
|
|
1793 |
|
|
1794 |
|limit free amount|
|
|
1795 |
|
|
1796 |
limit := FreeSpaceGCLimit.
|
|
1797 |
limit notNil ifTrue:[
|
|
1798 |
"/ if reclaimed space is below limit, we have to allocate more
|
|
1799 |
"/ oldSpace, to avoid excessive gcSteps (due to freeSpaceLimit
|
|
1800 |
"/ still not reached)
|
|
1801 |
"/
|
|
1802 |
free := self freeSpace + self freeListSpace.
|
|
1803 |
free < (limit * 3 // 2) ifTrue:[
|
|
1804 |
amount := FreeSpaceGCAmount.
|
|
1805 |
amount isNil ifTrue:[
|
|
1806 |
amount := limit * 3 // 2.
|
|
1807 |
].
|
|
1808 |
'OBJECTMEMORY: moreOldSpace to satisfy free-limit' infoPrintNL.
|
|
1809 |
self moreOldSpace:(amount - free + (64*1024))
|
|
1810 |
].
|
|
1811 |
].
|
|
1812 |
!
|
|
1813 |
|
133
|
1814 |
moreOldSpace:howMuch
|
|
1815 |
"allocate howMuch bytes more for old objects.
|
|
1816 |
This is done automatically, when running out of space, but makes
|
|
1817 |
sense, if its known in advance that a lot of memory is needed to
|
|
1818 |
avoid multiple reallocations and compresses.
|
310
|
1819 |
On systems which do not support the mmap (or equivalent) system call,
|
|
1820 |
this (currently) implies a compressing garbage collect - so its slow.
|
133
|
1821 |
Notice: this is a nonstandard interface - use only in special situations."
|
|
1822 |
|
|
1823 |
%{
|
253
|
1824 |
if (__isSmallInteger(howMuch))
|
159
|
1825 |
__moreOldSpace(__context, _intVal(howMuch));
|
133
|
1826 |
%}
|
|
1827 |
"
|
|
1828 |
ObjectMemory moreOldSpace:1000000
|
|
1829 |
"
|
|
1830 |
!
|
|
1831 |
|
202
|
1832 |
announceSpaceNeed:howMuch
|
|
1833 |
"announce to the memory system, that howMuch bytes of memory will be needed
|
|
1834 |
soon. The VM tries to prepare itself for this allocation to be performed
|
|
1835 |
with less overhead. For example, it could preallocate some memory in one
|
|
1836 |
big chunk (instead of doing many smaller reallocations later).
|
|
1837 |
Notice: this is a nonstandard interface - use only in special situations.
|
|
1838 |
Also, this does a background collect before the big chunk of memory is
|
|
1839 |
allocated, not locking other processes while doing so."
|
|
1840 |
|
|
1841 |
(howMuch < (self newSpaceSize // 2)) ifTrue:[
|
|
1842 |
self scavenge.
|
|
1843 |
].
|
|
1844 |
(self checkForFastNew:howMuch) ifFalse:[
|
|
1845 |
(howMuch > (self newSpaceSize // 2)) ifFalse:[
|
|
1846 |
self scavenge.
|
|
1847 |
].
|
|
1848 |
self incrementalGC.
|
|
1849 |
(self checkForFastNew:howMuch) ifFalse:[
|
|
1850 |
self moreOldSpace:howMuch
|
|
1851 |
]
|
|
1852 |
]
|
|
1853 |
|
|
1854 |
"
|
|
1855 |
ObjectMemory announceSpaceNeed:100000
|
|
1856 |
"
|
|
1857 |
!
|
|
1858 |
|
133
|
1859 |
announceOldSpaceNeed:howMuch
|
202
|
1860 |
"announce to the memory system, that howMuch bytes of memory will be needed
|
|
1861 |
soon, which is going to live longer (whatever that means).
|
|
1862 |
It first checks if the memory can be allocated without forcing a compressing
|
|
1863 |
GC. If not, the oldSpace is increased. This may also lead to a slow compressing
|
133
|
1864 |
collect. However, many smaller increases are avoided afterwards. Calling this
|
|
1865 |
method before allocating huge chunks of data may provide better overall performance.
|
|
1866 |
Notice: this is a nonstandard interface - use only in special situations."
|
|
1867 |
|
|
1868 |
(self checkForFastNew:howMuch) ifFalse:[
|
159
|
1869 |
self incrementalGC.
|
|
1870 |
(self checkForFastNew:howMuch) ifFalse:[
|
|
1871 |
self moreOldSpace:howMuch
|
|
1872 |
]
|
133
|
1873 |
]
|
|
1874 |
|
|
1875 |
"
|
|
1876 |
ObjectMemory announceOldSpaceNeed:1000000
|
|
1877 |
"
|
|
1878 |
!
|
|
1879 |
|
|
1880 |
oldSpaceIncrement
|
|
1881 |
"return the oldSpaceIncrement value. Thats the amount by which
|
|
1882 |
more memory is allocated in case the oldSpace gets filled up.
|
|
1883 |
In normal situations, the default value used in the VM is fine
|
|
1884 |
and there is no need to change it."
|
178
|
1885 |
|
|
1886 |
%{ /* NOCONTEXT */
|
133
|
1887 |
extern unsigned __oldSpaceIncrement();
|
|
1888 |
|
|
1889 |
RETURN (_MKSMALLINT( __oldSpaceIncrement(-1) ));
|
|
1890 |
%}
|
178
|
1891 |
"
|
|
1892 |
ObjectMemory oldSpaceIncrement
|
|
1893 |
"
|
133
|
1894 |
!
|
|
1895 |
|
|
1896 |
oldSpaceIncrement:amount
|
|
1897 |
"set the oldSpaceIncrement value. Thats the amount by which
|
|
1898 |
more memory is allocated in case the oldSpace gets filled up.
|
|
1899 |
In normal situations, the default value used in the VM is fine
|
|
1900 |
and there is no need to change it. This method returns the
|
|
1901 |
previous increment value."
|
178
|
1902 |
|
|
1903 |
%{ /* NOCONTEXT */
|
133
|
1904 |
extern unsigned __oldSpaceIncrement();
|
|
1905 |
|
253
|
1906 |
if (__isSmallInteger(amount)) {
|
159
|
1907 |
RETURN (_MKSMALLINT( __oldSpaceIncrement(_intVal(amount)) ));
|
133
|
1908 |
}
|
|
1909 |
%}
|
178
|
1910 |
"to change increment to 1Meg:"
|
|
1911 |
"
|
|
1912 |
ObjectMemory oldSpaceIncrement:1024*1024
|
|
1913 |
"
|
|
1914 |
!
|
|
1915 |
|
329
|
1916 |
oldSpaceCompressLimit:amount
|
|
1917 |
"set the limit for oldSpace compression. If more memory than this
|
|
1918 |
limit is in use, the system will not perform compresses on the oldspace,
|
|
1919 |
but instead do a mark&sweep GC followed by an oldSpace increase if not enough
|
|
1920 |
could be reclaimed. The default is currently some 8Mb, which is ok for workstations
|
|
1921 |
with 16..32Mb of physical memory. If your system has much more physical RAM,
|
|
1922 |
you may want to increase this limit.
|
|
1923 |
This method returns the previous increment value."
|
|
1924 |
|
|
1925 |
%{ /* NOCONTEXT */
|
|
1926 |
extern unsigned __compressingGCLimit();
|
|
1927 |
|
|
1928 |
if (__isSmallInteger(amount)) {
|
|
1929 |
RETURN (_MKSMALLINT( __compressingGCLimit(_intVal(amount)) ));
|
|
1930 |
}
|
|
1931 |
%}
|
|
1932 |
"to change the limit to 12Mb:"
|
|
1933 |
"
|
|
1934 |
ObjectMemory oldSpaceCompressLimit:12*1024*1024
|
|
1935 |
"
|
|
1936 |
!
|
|
1937 |
|
178
|
1938 |
fastMoreOldSpaceAllocation:aBoolean
|
|
1939 |
"this method turns on/off fastMoreOldSpace allocation.
|
|
1940 |
By default, this is turned off (false), which means that in case of
|
202
|
1941 |
a filled-up oldSpace, a GC is tried first before more oldSpace is allocated.
|
178
|
1942 |
This strategy is ok for the normal operation of the system,
|
|
1943 |
but behaves badly, if the program allocates huge data structures (say a
|
202
|
1944 |
game tree of 30Mb in size) which survives and therefore will not be reclaimed
|
178
|
1945 |
by a GC.
|
202
|
1946 |
Of course while building this tree, and the memory becomes full, the system
|
|
1947 |
would not know in advance, that the GC will not reclaim anything.
|
|
1948 |
|
178
|
1949 |
Setting fastOldSpaceIncrement to true will avoid this, by forcing the
|
|
1950 |
memory system to allocate more memory right away, without doing a GC first.
|
|
1951 |
|
|
1952 |
WARNING: make certain that this flag is turned off, after your huge data
|
|
1953 |
is allocated, since otherwise the system may continue to increase its
|
202
|
1954 |
virtual memory without ever checking for garbage.
|
310
|
1955 |
This method returns the previous value of the flag; typically this return
|
|
1956 |
value should be used to switch back."
|
178
|
1957 |
|
|
1958 |
%{ /* NOCONTEXT */
|
370
|
1959 |
extern int __fastMoreOldSpaceAllocation();
|
|
1960 |
|
178
|
1961 |
RETURN (__fastMoreOldSpaceAllocation(aBoolean == true ? 1 : 0) ? true : false);
|
|
1962 |
%}
|
310
|
1963 |
"
|
|
1964 |
|previousSetting|
|
|
1965 |
|
|
1966 |
previousSetting := ObjectMemory fastMoreOldSpaceAllocation:true.
|
|
1967 |
[
|
|
1968 |
...
|
|
1969 |
allocate your huge data
|
|
1970 |
...
|
|
1971 |
] valueNoOrOnUnwindDo:[
|
|
1972 |
ObjectMemory fastMoreOldSpaceAllocation:previousSetting
|
|
1973 |
]
|
|
1974 |
"
|
370
|
1975 |
|
|
1976 |
"
|
|
1977 |
|prev this|
|
|
1978 |
|
|
1979 |
prev := ObjectMemory fastMoreOldSpaceAllocation:true.
|
|
1980 |
ObjectMemory fastMoreOldSpaceAllocation:prev.
|
|
1981 |
^ prev
|
|
1982 |
"
|
|
1983 |
!
|
|
1984 |
|
|
1985 |
fastMoreOldSpaceLimit:aNumber
|
|
1986 |
"this method sets and returns the fastMoreOldSpace limit.
|
|
1987 |
If fastMoreOldSpaceAllocation is true, and the current oldSpace size is
|
|
1988 |
below this limit, the memory manager will NOT do a GC when running out of
|
|
1989 |
oldSpace, but instead quickly go ahead increasing the size of the oldSpace.
|
|
1990 |
Setting the limit to 0 turns off any limit (i.e. it will continue to
|
|
1991 |
increase the oldSpace forwever - actually, until the OS refuses to give us
|
|
1992 |
more memory). The returned value is the previous setting of the limit."
|
|
1993 |
|
|
1994 |
%{ /* NOCONTEXT */
|
|
1995 |
extern int __fastMoreOldSpaceLimit();
|
|
1996 |
|
|
1997 |
if (__isSmallInteger(aNumber)) {
|
|
1998 |
RETURN ( __MKSMALLINT( __fastMoreOldSpaceLimit(__intVal(aNumber))));
|
|
1999 |
}
|
|
2000 |
%}.
|
|
2001 |
self primitiveFailed
|
|
2002 |
|
|
2003 |
"
|
|
2004 |
|prev this|
|
|
2005 |
|
|
2006 |
prev := ObjectMemory fastMoreOldSpaceLimit:10*1024*1024.
|
|
2007 |
ObjectMemory fastMoreOldSpaceLimit:prev.
|
|
2008 |
^ prev
|
|
2009 |
"
|
133
|
2010 |
!
|
|
2011 |
|
|
2012 |
checkForFastNew:amount
|
|
2013 |
"this method returns true, if amount bytes could be allocated
|
|
2014 |
quickly (i.e. without forcing a full GC or compress).
|
|
2015 |
This can be used for smart background processes, which want to
|
|
2016 |
allocate big chunks of data without disturbing foreground processes
|
|
2017 |
too much. Such a process would check for fast-allocation, and perform
|
202
|
2018 |
incremental GC-steps if required. Thus, avoiding the long blocking pause
|
310
|
2019 |
due to a forced (non-incremental) GC.
|
|
2020 |
Especially: doing so will not block higher priority foreground processes.
|
|
2021 |
See an example use in Behavior>>niceBasicNew:.
|
133
|
2022 |
This is experimental and not guaranteed to be in future versions."
|
|
2023 |
|
178
|
2024 |
%{ /* NOCONTEXT */
|
370
|
2025 |
extern int __checkForFastNew();
|
133
|
2026 |
|
253
|
2027 |
if (__isSmallInteger(amount)) {
|
159
|
2028 |
if (! __checkForFastNew(_intVal(amount))) {
|
|
2029 |
RETURN (false);
|
|
2030 |
}
|
133
|
2031 |
}
|
|
2032 |
|
|
2033 |
%}.
|
|
2034 |
^ true
|
|
2035 |
!
|
|
2036 |
|
2
|
2037 |
turnGarbageCollectorOff
|
310
|
2038 |
"turn off the generational garbage collector by forcing new objects to be
|
|
2039 |
allocated directly in oldSpace (instead of newSpace)
|
178
|
2040 |
WARNING:
|
93
|
2041 |
This is somewhat dangerous: if collector is turned off,
|
77
|
2042 |
and too many objects are created, the system may run into trouble
|
|
2043 |
(i.e. oldSpace becomes full) and be forced to perform a full mark&sweep
|
202
|
2044 |
or even a compressing collect - making the overall realtime behavior worse.
|
93
|
2045 |
Use this only for special purposes or when realtime behavior
|
178
|
2046 |
is required for a limited time period."
|
|
2047 |
|
|
2048 |
%{ /* NOCONTEXT */
|
133
|
2049 |
__allocForceSpace(OLDSPACE);
|
1
|
2050 |
%}
|
|
2051 |
!
|
|
2052 |
|
2
|
2053 |
turnGarbageCollectorOn
|
202
|
2054 |
"turn garbage collector on again (see ObjectMemory>>turnGarbageCollectorOff)"
|
1
|
2055 |
|
178
|
2056 |
%{ /* NOCONTEXT */
|
133
|
2057 |
__allocForceSpace(9999);
|
1
|
2058 |
%}
|
178
|
2059 |
!
|
85
|
2060 |
|
|
2061 |
makeOld:anObject
|
93
|
2062 |
"move anObject into oldSpace.
|
133
|
2063 |
This method is for internal & debugging purposes only -
|
|
2064 |
it may vanish. Dont use it."
|
85
|
2065 |
%{
|
|
2066 |
if (__moveToOldSpace(anObject, __context) < 0) {
|
159
|
2067 |
RETURN (false);
|
93
|
2068 |
}
|
|
2069 |
%}.
|
|
2070 |
^ true
|
194
|
2071 |
!
|
|
2072 |
|
|
2073 |
tenureParameters:magic
|
|
2074 |
"this is pure magic and not for public eyes ...
|
202
|
2075 |
This method allows fine tuning the scavenger internals,
|
194
|
2076 |
in cooperation to some statistic & test programs.
|
202
|
2077 |
It is undocumented, secret and may vanish.
|
|
2078 |
If you play around here, the system may behave very strange."
|
194
|
2079 |
|
|
2080 |
%{ /* NOCONTEXT */
|
|
2081 |
__tenureParams(magic);
|
|
2082 |
%}.
|
370
|
2083 |
!
|
|
2084 |
|
|
2085 |
lockTenure:aBoolean
|
|
2086 |
"set/clear the tenureLock. If the lock is set, the system
|
|
2087 |
completely turns off tenuring, and objects remain in newSpace (forever).
|
|
2088 |
The system will completely operatate in the newSpace and no memory
|
|
2089 |
allocations from oldSpace are allowed, once this lock is
|
|
2090 |
set (except for explicit tenure calls).
|
|
2091 |
If any allocation request cannot be resoved, the VM raises a memory interrupt,
|
|
2092 |
clears the flag and returns nil. This, it automatically falls back into
|
|
2093 |
the normal mode of operation, to avoid big trouble (fail to allocate memory
|
|
2094 |
when handling the exception).
|
|
2095 |
|
|
2096 |
This interface can be used in applications, which are guaranteed to have their
|
|
2097 |
working set completely in the newSpace AND want to limit the worst case
|
|
2098 |
pause times to the worst case scavenge time (which itself is limitd by the
|
|
2099 |
size of the newSpace).
|
|
2100 |
I.e. systems which go into some event loop after initial startup,
|
|
2101 |
may turn on the tenureLock to make certain that no oldSpace memory is
|
|
2102 |
allocated in the future; thereby limiting any GC activity to newSpace
|
|
2103 |
scavenges only."
|
|
2104 |
|
|
2105 |
%{
|
|
2106 |
if (aBoolean == true) {
|
|
2107 |
__tenure(__context);
|
|
2108 |
}
|
|
2109 |
__lockTenure(aBoolean == true ? 1 : 0);
|
|
2110 |
%}
|
|
2111 |
!
|
|
2112 |
|
|
2113 |
newSpaceSize:newSize
|
|
2114 |
"change the size of the newSpace. To do this, the current contents
|
|
2115 |
of the newSpace may have to be tenured (if size is smaller).
|
|
2116 |
Returns false, if it failed for any reason.
|
|
2117 |
Experimental: this interface may valish without notice.
|
|
2118 |
|
|
2119 |
DANGER ALERT:
|
|
2120 |
be careful too big of a size may lead to longer scavenge pauses.
|
|
2121 |
Too small of a newSpace may lead to more CPU overhead, due to
|
|
2122 |
excessive scavenges. You have been warned."
|
|
2123 |
|
|
2124 |
%{
|
|
2125 |
extern int __setNewSpaceSize();
|
|
2126 |
|
|
2127 |
if (__isSmallInteger(newSize)) {
|
|
2128 |
RETURN (__setNewSpaceSize(__intVal(newSize)) ? true : false);
|
|
2129 |
}
|
|
2130 |
%}.
|
|
2131 |
self primitiveFailed
|
|
2132 |
|
|
2133 |
" less absolute CPU overhead (but longer pauses):
|
|
2134 |
|
|
2135 |
ObjectMemory newSpaceSize:800*1024
|
|
2136 |
"
|
|
2137 |
|
|
2138 |
" smaller pauses, but more overall CPU overhead:
|
|
2139 |
|
|
2140 |
ObjectMemory newSpaceSize:200*1024
|
|
2141 |
"
|
|
2142 |
|
|
2143 |
" the default:
|
|
2144 |
|
|
2145 |
ObjectMemory newSpaceSize:400*1024
|
|
2146 |
"
|
178
|
2147 |
! !
|
|
2148 |
|
362
|
2149 |
!ObjectMemory class ignoredMethodsFor:'object finalization'!
|
290
|
2150 |
|
|
2151 |
allShadowObjectsDo:aBlock
|
|
2152 |
"evaluate the argument, aBlock for all known shadow objects"
|
|
2153 |
%{
|
326
|
2154 |
__allShadowObjectsDo(&aBlock COMMA_CON);
|
290
|
2155 |
%}
|
362
|
2156 |
! !
|
|
2157 |
|
|
2158 |
!ObjectMemory class methodsFor:'object finalization'!
|
290
|
2159 |
|
|
2160 |
allChangedShadowObjectsDo:aBlock
|
|
2161 |
"evaluate the argument, aBlock for all known shadow objects which have
|
|
2162 |
lost a pointer recently."
|
|
2163 |
%{
|
326
|
2164 |
__allChangedShadowObjectsDo(&aBlock COMMA_CON);
|
290
|
2165 |
%}
|
|
2166 |
!
|
|
2167 |
|
291
|
2168 |
finalize
|
|
2169 |
"tell all weak objects that something happened."
|
|
2170 |
|
|
2171 |
self allChangedShadowObjectsDo:[:aShadowArray |
|
|
2172 |
aShadowArray lostPointer.
|
|
2173 |
]
|
|
2174 |
!
|
|
2175 |
|
290
|
2176 |
disposeInterrupt
|
|
2177 |
"this is triggered by the garbage collector,
|
|
2178 |
whenever any shadowArray looses a pointer."
|
|
2179 |
|
|
2180 |
FinalizationSemaphore notNil ifTrue:[
|
|
2181 |
"/
|
|
2182 |
"/ background finalizer is waiting ...
|
|
2183 |
"/
|
|
2184 |
FinalizationSemaphore signal
|
|
2185 |
] ifFalse:[
|
|
2186 |
"/
|
|
2187 |
"/ do it right here
|
|
2188 |
"/
|
291
|
2189 |
self finalize
|
290
|
2190 |
]
|
|
2191 |
!
|
|
2192 |
|
|
2193 |
startBackgroundFinalizationAt:aPriority
|
|
2194 |
"start a process doing finalization work in the background.
|
|
2195 |
Can be used to reduce the pauses created by finalization.
|
|
2196 |
Normally, these pauses are not noticed; however if you have (say)
|
|
2197 |
ten thousands of weak objects, these could become long enough to
|
|
2198 |
make background finalization usefull.
|
|
2199 |
WARNING: background finalization may lead to much delayed freeing of
|
|
2200 |
system resources. Especially, you may temporarily run out of free
|
|
2201 |
color table entries or fileDescriptors etc. Use at your own risk (if at all)"
|
|
2202 |
|
|
2203 |
|p|
|
|
2204 |
|
|
2205 |
"/
|
|
2206 |
"/ its not useful, to run it more than once
|
|
2207 |
"/
|
|
2208 |
BackgroundFinalizationProcess notNil ifTrue:[
|
|
2209 |
BackgroundFinalizationProcess priority:aPriority.
|
|
2210 |
^ self
|
|
2211 |
].
|
|
2212 |
|
|
2213 |
FinalizationSemaphore := Semaphore new.
|
|
2214 |
|
|
2215 |
p :=
|
|
2216 |
[
|
|
2217 |
[
|
|
2218 |
[true] whileTrue:[
|
|
2219 |
"
|
|
2220 |
wait till something to do ...
|
|
2221 |
"
|
|
2222 |
FinalizationSemaphore wait.
|
|
2223 |
"
|
|
2224 |
... and do it
|
|
2225 |
"
|
291
|
2226 |
self finalize
|
290
|
2227 |
]
|
|
2228 |
] valueOnUnwindDo:[
|
|
2229 |
BackgroundFinalizationProcess := nil.
|
|
2230 |
FinalizationSemaphore := nil
|
|
2231 |
]
|
|
2232 |
] newProcess.
|
|
2233 |
p name:'background finalizer'.
|
|
2234 |
p priority:aPriority.
|
339
|
2235 |
p restartable:true.
|
290
|
2236 |
p resume.
|
|
2237 |
BackgroundFinalizationProcess := p
|
|
2238 |
|
|
2239 |
"
|
|
2240 |
ObjectMemory startBackgroundFinalizationAt:5
|
|
2241 |
"
|
|
2242 |
!
|
|
2243 |
|
|
2244 |
stopBackgroundFinalization
|
|
2245 |
"stop the background finalizer"
|
|
2246 |
|
|
2247 |
BackgroundFinalizationProcess notNil ifTrue:[
|
|
2248 |
BackgroundFinalizationProcess terminate.
|
|
2249 |
BackgroundFinalizationProcess := nil
|
|
2250 |
].
|
|
2251 |
|
|
2252 |
"
|
|
2253 |
ObjectMemory stopBackgroundFinalization
|
|
2254 |
"
|
|
2255 |
! !
|
|
2256 |
|
178
|
2257 |
!ObjectMemory class methodsFor:'physical memory access'!
|
93
|
2258 |
|
|
2259 |
newSpacePagesDo:aBlock
|
|
2260 |
"evaluates aBlock for all pages in the newSpace, passing
|
|
2261 |
the pages address as argument.
|
|
2262 |
For internal & debugging use only."
|
|
2263 |
%{
|
|
2264 |
if (__newSpacePagesDo(&aBlock COMMA_CON) < 0) {
|
159
|
2265 |
RETURN (false);
|
85
|
2266 |
}
|
|
2267 |
%}.
|
|
2268 |
^ true
|
|
2269 |
!
|
|
2270 |
|
|
2271 |
oldSpacePagesDo:aBlock
|
|
2272 |
"evaluates aBlock for all pages in the oldSpace, passing
|
|
2273 |
the pages address as argument.
|
93
|
2274 |
For internal & debugging use only."
|
85
|
2275 |
%{
|
|
2276 |
if (__oldSpacePagesDo(&aBlock COMMA_CON) < 0) {
|
159
|
2277 |
RETURN (false);
|
85
|
2278 |
}
|
|
2279 |
%}.
|
|
2280 |
^ true
|
|
2281 |
!
|
|
2282 |
|
93
|
2283 |
collectedOldSpacePagesDo:aBlock
|
|
2284 |
"evaluates aBlock for all pages in the prev. oldSpace, passing
|
|
2285 |
the pages address as argument.
|
|
2286 |
For internal & debugging use only."
|
|
2287 |
%{
|
|
2288 |
if (__collectedOldSpacePagesDo(&aBlock COMMA_CON) < 0) {
|
159
|
2289 |
RETURN (false);
|
93
|
2290 |
}
|
|
2291 |
%}.
|
|
2292 |
^ true
|
|
2293 |
!
|
|
2294 |
|
85
|
2295 |
pageIsInCore:aPageNumber
|
|
2296 |
"return true, if the page (as enumerated via oldSpacePagesDo:)
|
|
2297 |
is in memory; false, if currently paged out. For internal
|
93
|
2298 |
use / monitors only; may vanish.
|
|
2299 |
NOTICE: not all systems provide this information; on those that
|
|
2300 |
do not, true is returned for all pages."
|
85
|
2301 |
%{
|
|
2302 |
#ifdef HAS_MINCORE
|
|
2303 |
int pageSize = getpagesize();
|
|
2304 |
char result[10];
|
|
2305 |
INT addr;
|
|
2306 |
|
253
|
2307 |
if (__isSmallInteger(aPageNumber)) {
|
159
|
2308 |
addr = _intVal(aPageNumber) & ~(pageSize - 1);
|
85
|
2309 |
} else {
|
159
|
2310 |
addr = ((INT)aPageNumber) & ~(pageSize - 1);
|
85
|
2311 |
}
|
|
2312 |
if (mincore(addr, pageSize-1, result) < 0) {
|
159
|
2313 |
RETURN (true);
|
85
|
2314 |
}
|
|
2315 |
RETURN ((result[0] & 1) ? true : false);
|
|
2316 |
#endif
|
|
2317 |
%}.
|
|
2318 |
"OS does not supply this info - assume yes"
|
|
2319 |
^ true
|
|
2320 |
! !
|
|
2321 |
|
13
|
2322 |
!ObjectMemory class methodsFor:'low memory handling'!
|
|
2323 |
|
|
2324 |
memoryInterrupt
|
|
2325 |
"when a low-memory condition arises, ask all classes to
|
290
|
2326 |
remove possibly cached data. You may help the system a bit,
|
|
2327 |
in providing a lowSpaceCleanup method in your classes which have
|
|
2328 |
lots of data kept somewhere (usually, cached data).
|
|
2329 |
- this may or may not help."
|
13
|
2330 |
|
308
|
2331 |
Smalltalk allBehaviorsDo:[:aClass |
|
159
|
2332 |
aClass lowSpaceCleanup
|
13
|
2333 |
].
|
|
2334 |
|
178
|
2335 |
"/ self error:'almost out of memory'
|
|
2336 |
'almost out of memory' errorPrintNL.
|
|
2337 |
|
|
2338 |
LowSpaceSemaphore signalIf.
|
13
|
2339 |
! !
|
|
2340 |
|
1
|
2341 |
!ObjectMemory class methodsFor:'system management'!
|
|
2342 |
|
|
2343 |
loadClassBinary:aClassName
|
|
2344 |
"find the object file for aClassName and -if found - load it;
|
|
2345 |
this one loads precompiled object files"
|
|
2346 |
|
357
|
2347 |
|fName newClass|
|
1
|
2348 |
|
|
2349 |
fName := self fileNameForClass:aClassName.
|
|
2350 |
fName notNil ifTrue:[
|
202
|
2351 |
Class withoutUpdatingChangesDo:
|
159
|
2352 |
[
|
|
2353 |
self loadBinary:(fName , '.o')
|
|
2354 |
].
|
|
2355 |
newClass := self at:(aClassName asSymbol).
|
|
2356 |
(newClass notNil and:[newClass implements:#initialize]) ifTrue:[
|
|
2357 |
newClass initialize
|
|
2358 |
]
|
1
|
2359 |
]
|
|
2360 |
!
|
|
2361 |
|
77
|
2362 |
imageName
|
|
2363 |
"return the filename of the current image, or nil
|
|
2364 |
if not running from an image."
|
|
2365 |
|
|
2366 |
^ ImageName
|
159
|
2367 |
|
|
2368 |
"
|
202
|
2369 |
ObjectMemory imageName
|
|
2370 |
"
|
|
2371 |
!
|
|
2372 |
|
|
2373 |
imageBaseName
|
|
2374 |
"return a reasonable filename to use as baseName (i.e. without extension).
|
|
2375 |
This is the filename of the current image (without '.img') or,
|
|
2376 |
if not running from an image, the default name 'st'"
|
|
2377 |
|
|
2378 |
|nm|
|
|
2379 |
|
|
2380 |
nm := ImageName.
|
|
2381 |
(nm isNil or:[nm isBlank]) ifTrue:[
|
|
2382 |
^ 'st'
|
|
2383 |
].
|
|
2384 |
(nm endsWith:'.sav') ifTrue:[
|
359
|
2385 |
nm := nm copyWithoutLast:4
|
202
|
2386 |
].
|
|
2387 |
(nm endsWith:'.img') ifTrue:[
|
359
|
2388 |
^ nm copyWithoutLast:4
|
202
|
2389 |
].
|
|
2390 |
^ nm
|
|
2391 |
|
|
2392 |
"
|
|
2393 |
ObjectMemory imageBaseName
|
159
|
2394 |
"
|
77
|
2395 |
!
|
|
2396 |
|
22
|
2397 |
nameForSnapshot
|
159
|
2398 |
"return a reasonable filename to store the snapshot image into.
|
|
2399 |
This is the filename of the current image or,
|
22
|
2400 |
if not running from an image, the default name 'st.img'"
|
|
2401 |
|
202
|
2402 |
^ self imageBaseName , '.img'
|
|
2403 |
|
|
2404 |
"
|
|
2405 |
ObjectMemory nameForSnapshot
|
|
2406 |
"
|
|
2407 |
!
|
|
2408 |
|
|
2409 |
nameForSources
|
|
2410 |
"return a reasonable filename to store the sources into.
|
|
2411 |
This is the basename of the current image with '.img' replaced
|
|
2412 |
by '.src', or, if not running from an image, the default name 'st.src'"
|
|
2413 |
|
|
2414 |
^ self imageBaseName , '.src'
|
159
|
2415 |
|
|
2416 |
"
|
202
|
2417 |
ObjectMemory nameForSources
|
|
2418 |
"
|
|
2419 |
!
|
|
2420 |
|
|
2421 |
nameForChanges
|
|
2422 |
"return a reasonable filename to store the changes into.
|
|
2423 |
This is the basename of the current image with '.img' replaced
|
|
2424 |
by '.chg', or, if not running from an image, the default name 'st.chg'"
|
|
2425 |
|
|
2426 |
^ 'changes'.
|
360
|
2427 |
|
|
2428 |
"/ future versions will have:
|
|
2429 |
"/ (requires some additionas at other places)
|
|
2430 |
"/
|
|
2431 |
"/ ^ self imageBaseName , '.chg'
|
202
|
2432 |
|
|
2433 |
"
|
|
2434 |
ObjectMemory nameForChanges
|
159
|
2435 |
"
|
22
|
2436 |
!
|
|
2437 |
|
1
|
2438 |
snapShot
|
159
|
2439 |
"create a snapshot file containing all of the current state."
|
1
|
2440 |
|
22
|
2441 |
self snapShotOn:(self nameForSnapshot)
|
1
|
2442 |
|
159
|
2443 |
"
|
|
2444 |
ObjectMemory snapShot
|
|
2445 |
"
|
1
|
2446 |
!
|
|
2447 |
|
|
2448 |
snapShotOn:aFileName
|
329
|
2449 |
"create a snapshot in the given file.
|
|
2450 |
If the file exists, save it for backup.
|
|
2451 |
Return true if the snapshot worked, false if it failed for some reason.
|
|
2452 |
Notify dependents before and after the snapshot operation."
|
1
|
2453 |
|
159
|
2454 |
|ok oldImageName|
|
|
2455 |
|
|
2456 |
"
|
|
2457 |
keep a save version - just in case something
|
|
2458 |
bad happens while writing the image.
|
|
2459 |
(could be st/x internal error or file-system errors etc)
|
|
2460 |
"
|
|
2461 |
(OperatingSystem isValidPath:aFileName) ifTrue:[
|
|
2462 |
OperatingSystem renameFile:aFileName to:(aFileName , '.sav').
|
|
2463 |
].
|
22
|
2464 |
|
93
|
2465 |
"
|
|
2466 |
give others a chance to fix things
|
|
2467 |
"
|
329
|
2468 |
self changed:#save. "/ will vanish ...
|
|
2469 |
self changed:#aboutToSnapshot. "/ ... for ST-80 compatibility
|
13
|
2470 |
|
93
|
2471 |
"
|
|
2472 |
ST-80 compatibility; send #preSnapshot to all classes
|
|
2473 |
"
|
202
|
2474 |
Smalltalk allBehaviorsDo:[:aClass |
|
159
|
2475 |
aClass preSnapshot
|
93
|
2476 |
].
|
|
2477 |
|
159
|
2478 |
"
|
|
2479 |
save the name with it ...
|
|
2480 |
"
|
|
2481 |
oldImageName := ImageName.
|
|
2482 |
ImageName := aFileName.
|
|
2483 |
ok := self primSnapShotOn:aFileName.
|
|
2484 |
ImageName := oldImageName.
|
|
2485 |
|
|
2486 |
ok ifTrue:[
|
|
2487 |
Class addChangeRecordForSnapshot:aFileName.
|
329
|
2488 |
].
|
159
|
2489 |
|
|
2490 |
|
329
|
2491 |
"
|
|
2492 |
ST-80 compatibility; send #postSnapshot to all classes
|
|
2493 |
"
|
|
2494 |
Smalltalk allBehaviorsDo:[:aClass |
|
|
2495 |
aClass postSnapshot
|
159
|
2496 |
].
|
329
|
2497 |
self changed:#finishedSnapshot. "/ ST-80 compatibility
|
159
|
2498 |
^ ok
|
|
2499 |
|
|
2500 |
"
|
|
2501 |
ObjectMemory snapShotOn:'myimage.img'
|
|
2502 |
"
|
|
2503 |
!
|
|
2504 |
|
|
2505 |
primSnapShotOn:aFileName
|
|
2506 |
"create a snapshot in the given file.
|
|
2507 |
Low level entry. Does not notify classes or write an entry to
|
|
2508 |
the changes file. Also, no image backup is created. Returns true if
|
|
2509 |
the snapshot worked, false if it failed for some reason.
|
|
2510 |
This method should not be used in normal cases."
|
|
2511 |
|
|
2512 |
|ok|
|
|
2513 |
|
13
|
2514 |
%{ /* STACK:32000 */
|
|
2515 |
|
1
|
2516 |
OBJ __snapShotOn();
|
159
|
2517 |
OBJ funny = @symbol(funnySnapshotSymbol);
|
1
|
2518 |
|
56
|
2519 |
if (__isString(aFileName)) {
|
356
|
2520 |
__BLOCKINTERRUPTS();
|
159
|
2521 |
ok = __snapShotOn(__context, _stringVal(aFileName), funny);
|
356
|
2522 |
__UNBLOCKINTERRUPTS();
|
1
|
2523 |
}
|
159
|
2524 |
%}.
|
22
|
2525 |
^ ok
|
1
|
2526 |
!
|
|
2527 |
|
|
2528 |
applicationImageOn:aFileName for:startupClass selector:startupSelector
|
|
2529 |
"create a snapshot which will come up without any views
|
93
|
2530 |
but starts up an application by sending startupClass the startupSelector.
|
312
|
2531 |
This exists to nail down an idea I tried once.
|
|
2532 |
It is absolutely EXPERIMENTAL and unfinished. Dont use this method."
|
1
|
2533 |
|
2
|
2534 |
|viewsKnown savedIdleBlocks savedTimeoutBlocks savedTranscript
|
|
2535 |
savedRoot|
|
1
|
2536 |
|
|
2537 |
viewsKnown := Display knownViews.
|
|
2538 |
savedTranscript := Transcript.
|
2
|
2539 |
savedRoot := RootView.
|
1
|
2540 |
|
335
|
2541 |
"a kludge: save image with modified knownViews,
|
10
|
2542 |
and also Transcript set to StdErr ..."
|
1
|
2543 |
|
|
2544 |
Display knownViews:nil.
|
2
|
2545 |
RootView := nil.
|
|
2546 |
|
1
|
2547 |
Transcript := Stderr.
|
10
|
2548 |
Smalltalk startupClass:startupClass selector:startupSelector arguments:nil.
|
1
|
2549 |
self snapShotOn:aFileName.
|
10
|
2550 |
Smalltalk startupClass:nil selector:nil arguments:nil.
|
1
|
2551 |
|
2
|
2552 |
RootView := savedRoot.
|
1
|
2553 |
Transcript := savedTranscript.
|
|
2554 |
Display knownViews:viewsKnown.
|
335
|
2555 |
|
|
2556 |
"
|
|
2557 |
ObjectMemory applicationImageOn:'draw.img' for:DrawTool selector:#start
|
|
2558 |
"
|
1
|
2559 |
!
|
|
2560 |
|
|
2561 |
minimumApplicationImageOn:aFileName for:startupClass selector:startupSelector
|
|
2562 |
"create a snapshot which will come up without any views
|
|
2563 |
but starts up an application by sending startupClass the startupSelector.
|
93
|
2564 |
All unneeded info is stripped from the saved image.
|
312
|
2565 |
This exists to nail down an idea I tried once.
|
|
2566 |
It is absolutely EXPERIMENTAL and unfinished. Dont use this method."
|
1
|
2567 |
|
|
2568 |
"create a temporary image, for continuation"
|
|
2569 |
self snapShotOn:'temp.img'.
|
|
2570 |
|
|
2571 |
Display knownViews do:[:aView |
|
159
|
2572 |
aView notNil ifTrue:[
|
|
2573 |
aView superView isNil ifTrue:[
|
|
2574 |
aView destroy
|
|
2575 |
]
|
|
2576 |
]
|
1
|
2577 |
].
|
|
2578 |
|
|
2579 |
self stripImage.
|
|
2580 |
|
|
2581 |
self applicationImageOn:aFileName for:startupClass selector:startupSelector.
|
|
2582 |
|
|
2583 |
"continue in old image"
|
|
2584 |
|
|
2585 |
OperatingSystem exec:(Arguments at:1)
|
159
|
2586 |
withArguments:#('smalltalk' '-i' 'temp.img') , (Arguments copyFrom:2)
|
1
|
2587 |
|
335
|
2588 |
"
|
|
2589 |
ObjectMemory minimumApplicationImageOn:'draw1.img' for:DrawTool selector:#start
|
|
2590 |
ObjectMemory applicationImageOn:'draw2.img' for:DrawTool selector:#start
|
|
2591 |
"
|
1
|
2592 |
!
|
|
2593 |
|
|
2594 |
stripImage
|
93
|
2595 |
"remove all unneeded stuff from the image - much more is possible here.
|
|
2596 |
EXPERIMENTAL and unfinished. Dont use this method."
|
1
|
2597 |
|
2
|
2598 |
"remove all class comments & source"
|
1
|
2599 |
|
2
|
2600 |
Smalltalk allBehaviorsDo:[:aClass |
|
159
|
2601 |
aClass setComment:nil.
|
|
2602 |
aClass methodArray do:[:aMethod |
|
|
2603 |
aMethod source:''.
|
|
2604 |
aMethod category:#none
|
|
2605 |
]
|
1
|
2606 |
].
|
335
|
2607 |
|
|
2608 |
"remove some developpers classes"
|
|
2609 |
|
|
2610 |
Smalltalk at:#Compiler put:Parser.
|
|
2611 |
Smalltalk at:#Debugger put:MiniDebugger.
|
|
2612 |
Smalltalk at:#Inspector put:MiniInspector.
|
|
2613 |
Smalltalk at:#FileBrowser put:nil.
|
|
2614 |
Smalltalk at:#SystemBrowser put:nil.
|
|
2615 |
Debugger newDebugger.
|
|
2616 |
|
1
|
2617 |
self garbageCollect
|
|
2618 |
! !
|
362
|
2619 |
|
|
2620 |
!ObjectMemory class methodsFor:'ST-80 compatibility'!
|
|
2621 |
|
|
2622 |
availableFreeBytes
|
|
2623 |
^ self freeSpace + self freeListSpace
|
|
2624 |
|
|
2625 |
"
|
|
2626 |
ObjectMemory availableFreeBytes
|
|
2627 |
"
|
|
2628 |
!
|
|
2629 |
|
|
2630 |
current
|
|
2631 |
^ self
|
|
2632 |
!
|
|
2633 |
|
|
2634 |
growMemoryBy:numberOfBytes
|
|
2635 |
^ self moreOldSpace:numberOfBytes
|
|
2636 |
!
|
|
2637 |
|
|
2638 |
numOopsNumBytes
|
|
2639 |
^ Array with:(self numberOfObjects)
|
|
2640 |
with:(self bytesUsed)
|
|
2641 |
|
|
2642 |
"
|
|
2643 |
ObjectMemory numOopsNumBytes
|
|
2644 |
"
|
|
2645 |
!
|
|
2646 |
|
|
2647 |
globalCompactingGC
|
|
2648 |
self garbageCollect
|
|
2649 |
!
|
|
2650 |
|
|
2651 |
compactingGC
|
|
2652 |
self garbageCollect
|
|
2653 |
! !
|
|
2654 |
|