eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'WeakArray':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: WeakArray


Inheritance:

   Object
   |
   +--Collection
      |
      +--SequenceableCollection
         |
         +--ArrayedCollection
            |
            +--WeakArray

Package:
stx:libbasic
Category:
Collections-Weak
Version:
rev: 1.85 date: 2019/05/27 13:04:51
user: cg
file: WeakArray.st directory: libbasic
module: stx stc-classLibrary: libbasic
Author:
Claus Gittinger

Description:


WeakArrays can be used to trace disposal of objects; in contrast to other
objects, references by WeakArrays will NOT keep an object from being
garbage collected.
Instead, whenever an object kept in a WeakArray dies, its entry is set to a SmallInteger,
and the WeakArray is informed by the storage manager. The WeakArray itself
then informs possible dependents via the dependency mechanism.

WeakArrays are used to track disposal of objects which keep external
world resources. For example, FileStreams must close their underlying
file when disposed (otherwise you could run out of OS filedescriptors).
This can be done by keeping the FileStream objects in a weakArray, and
keep a parallel array of filedescriptors. Whenever a fileStream is
freed, search both arrays for an index where the stream is set to a SmallInteger, but the
filedescriptor is non-nil. Then close that file, and nil the filedescriptor
entry. Notice, that there is a class (Registry) which does exactly this in
a more programmer friendly way.

Another application is caching of data: keep it in a weakArray, so the
data in that cache will not be unreclaimable due to being cached.
(for example, the ResourcePack class uses a WeakArray to cache recently
 used resource data for a while).

The way in which weakArrays get informed by the runtime system is via
an interrupt (DisposeInterrupt) which is first sent to the disposeHandler
(typically ObjectMemory). ObjectMemory then takes the required steps to
notify all weakArrays via the #lostPointer message.
The reason for not sending messages directly from the VM is to make it
possible to run the finalization code at lower priority or from another class.
Also, as a side effect, it is possible to delay finalization by blocking
interrupts. (thus, the actual sending of the #lostPointer message is under
control of Smalltalk code, which is modifyable).


A weakArray notifies its dependents via normal dependency notfications.


As a possible option, we could perform the weakArray scanning only in
the oldSpace reclamation code - this would remove most of the overhead,
but will lead to much longer delayed finalization .... we will see.


[instance variables:]

    dependents                  get informed via #change notifiction
                                that the weakArray has lost pointers.
                                Having the dependents here is an optimization.

[class variables:]

    RegistrationFailedSignal    raised if a weakArray cannot be
                                registered by the VM. This only happens,
                                if the VM has to resize its internal tables
                                and is running out of malloc-memory.

[memory requirements:]
    OBJ-HEADER + (size * ptr-size) + ptr-size
               + sizeof(dependents-collection)


Hints:


WeakArray handling adds small some overhead to the VM
(each weakarray is scanned after each GC).
It is uncertain, if the current mechanism works well
with (say) ten-thousands of weakArrays.
We had the system running with >2000 weakArrays, some being quite
big for a while and had a few percent of added gc time.
The system as delivered creates between 50 and 100 weakArrays,
but with many dependents, this number may grow.
If you need the dependency mechanism on a huge number of objects,
consider adding a (non-weak) dependents field to your class
- take the implementation of Model as a guide (or subclass them
from Model).

Related information:

    Array
    WeakIdentitySet
    WeakIdentityDictionary
    Registry
    Model

Class protocol:

initialization
o  initialize
adjust my class flags and setup the private signal

instance creation
o  basicNew: size
return a new weakArray with size slots

queries
o  isBuiltInClass
return true if this class is known by the run-time-system.
Here, true is returned for myself, false for subclasses.


Instance protocol:

GC registration
o  registerAsWeakArray
register the receiver in the VM -
i.e. tell the VM to nil disposed entries in the receiver
and notify the disposeInterruptHandler whenever that happened.

accessing
o  at: index
return the indexed instance variable with index, anInteger.
Reimplemented here for IGC readBarrier.
(You don't have to understand this.)

o  at: index ifAbsent: exceptionValue
return the indexed instance variable with index, anInteger,
or exceptionValue if the index is invalid.
Reimplemented here for IGC readBarrier.
(You don't have to understand this.)

o  at: index ifInvalid: exceptionalValue
return the indexed instance variable with index, anInteger,
but only if still valid; otherwise return the value from exceptionalValue

o  at: index put: someObject
store someObject in the weakArray at some index.

o  basicAt: index
return the indexed instance variable with index, anInteger.
Reimplemented here for IGC readBarrier.
(You don't have to understand this.)

o  basicAt: index put: someObject
store someObject in the weakArray at some index.

copying
o  skipInstvarIndexInDeepCopy: index
a helper for deepCopy; only indices for which this method returns
false are copied in a deep copy.

copying-private
o  postCopy
copying alone does not really help - we have to tell
the VM, that there is a new WeakArray around ...
Q: who copies weakArrays ?

o  postDeepCopy

dependents access
o  addDependent: anObject
make the argument, anObject be a dependent of the receiver

o  dependents
return the dependents of the receiver

o  dependents: aCollectionOrNil
set the dependents of the receiver

o  dependentsDo: aBlock
evaluate aBlock for all of my dependents

o  removeDependent: anObject
make the argument, anObject be independent of the receiver

enumerating
o  do: aBlock
evaluate the argument, aBlock for each element in the collection.
- reimplemented for IGC readBarrier.
You don't have to understand this.

o  forAllDeadIndicesDo: aBlock
evaluate the argument, aBlock for all indices where elements have been
replaced by zero (due to a collected object).
Be aware, that while indices are being enumerated, other
slots may change iff the garbage collector finds new garbage.

o  forAllDeadIndicesDo: aBlock replacingCorpsesWith: newValue
evaluate the argument, aBlock for all indices where elements have been
replaced by a SmallInteger (due to a collected object), and replace the element
with newValue.
In the current implementation, the block sees the newValue (i.e. it is
changed before the block is called); this behavior is not guaranteed
with future versions.
Be aware, that while indices are being enumerated, other
slots may change iff the garbage collector finds new garbage.

o  nilAllCorpsesAndDo: aBlock
evaluate the argument, aBlock for all indices where elements have been
cleared (due to a collected object), nil the entry.

o  nonNilElementsDo: aBlock
evaluate the argument, aBlock for each non-nil element

o  validElementsDo: aBlock
evaluate the argument, aBlock for each non-nil/non-evacuated element

notification
o  lostPointer
I lost a pointer; tell dependents.
This is sent from the finalization code in ObjectMemory.

testing
o  isWeakCollection
return true, if the receiver has weak references to its elements.



ST/X 7.2.0.0; WebServer 1.670 at bd0aa1f87cdd.unknown:8081; Fri, 19 Apr 2024 10:49:09 GMT