1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
|
.. sources:
`<https://info.ravenbrook.com/project/mps/doc/2002-06-18/obsolete-mminfo/mmdoc/protocol/mps/arena/>`_
`<https://info.ravenbrook.com/project/mps/master/design/arena/>`_
.. index::
single: arena
.. _topic-arena:
Arenas
======
An arena is an object that encapsulates the state of the Memory Pool
System, and tells it where to get the memory it manages. You typically
start a session with the MPS by creating an arena with
:c:func:`mps_arena_create_k` and end the session by destroying it with
:c:func:`mps_arena_destroy`. The only functions you might need to call
before making an arena are :term:`telemetry system` functions like
:c:func:`mps_telemetry_set` and the :term:`plinth` function
:c:func:`mps_lib_assert_fail_install`.
Before destroying an arena, you must first destroy all objects and
data in it, as usual for abstract data types in the MPS. If you can't
destroy the arena properly (for example, because your program has
crashed and you are at the debugger prompt), you can still call
:c:func:`mps_telemetry_flush` explicitly.
Other types of objects in the MPS are created "in the arena". They are
part of the world within the arena, and may interact and affect each
other.
.. index::
single: arena; multiple
.. note::
The MPS allows creation of multiple arenas, but you would only do
this in unusual circumstances, for example during the integration
of two pieces of software that each independently uses the MPS.
Arenas do not normally interact, but they compete with each other
for resources, and references from one arena to another are not
traced, though you *can* declare :term:`roots` pointing
from one arena to another. It is not efficient to have multiple
arenas containing :term:`automatically managed <automatic memory
management>` :term:`pools`: if you find yourself in this
situation it's best to find a way to move all the automatically
managed pools to one arena.
The open source MPS comes with two classes of arena,
:ref:`topic-arena-client` and :ref:`topic-arena-vm`. These differ in
the way that they acquire the memory to be managed.
.. note::
The MPS is designed to be extensible with new arena classes. If
you need features that are not provided by any of the open source
arena classes, :ref:`contact us <contact>`.
.. c:type:: mps_arena_t
The type of :term:`arenas`.
An arena is responsible for requesting :term:`memory (3)` from
the operating system, making it available to :term:`pools`,
and for :term:`garbage collection`.
.. c:type:: mps_arena_class_t
The type of :term:`arena classes`.
.. c:function:: mps_res_t mps_arena_create_k(mps_arena_t *arena_o, mps_arena_class_t arena_class, mps_arg_s args[])
Create an :term:`arena`.
``arena_o`` points to a location that will hold a pointer to the new
arena.
``arena_class`` is the :term:`arena class`.
``args`` are :term:`keyword arguments` specific to the arena
class. See the documentation for the arena class.
Returns :c:macro:`MPS_RES_OK` if the arena is created
successfully, or another :term:`result code` otherwise.
The arena persists until it is destroyed by calling
:c:func:`mps_arena_destroy`.
.. c:function:: void mps_arena_destroy(mps_arena_t arena)
Destroy an :term:`arena`.
``arena`` is the arena to destroy.
This function checks the consistency of the arena, flushes the
:term:`telemetry stream` and destroys the arena's internal control
structures. Additionally, :term:`virtual memory arenas` return
their reserved address space to the operating system if possible.
It is an error to destroy an arena without first destroying all
:term:`generation chains`, :term:`object formats`, :term:`pools`
and :term:`roots` created in the arena, and deregistering all
:term:`threads` registered with the arena.
.. index::
single: arena class; client
single: client arena class
.. _topic-arena-client:
Client arenas
-------------
::
#include "mpsacl.h"
.. c:function:: mps_arena_class_t mps_arena_class_cl(void)
Return the :term:`arena class` for a :term:`client arena`.
A client arena gets its managed memory from the :term:`client
program`. This memory chunk is passed when the arena is created.
When creating a client arena, :c:func:`mps_arena_create_k` requires two
:term:`keyword arguments`:
* :c:macro:`MPS_KEY_ARENA_CL_BASE` (type :c:type:`mps_addr_t`) is
the :term:`address` of the chunk of memory that will be managed
by the arena.
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`) is its
size.
It also accepts three optional keyword arguments:
* :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of memory, in :term:`bytes (1)`, that the MPS
will use out of the provided chunk (or chunks, if the arena is
extended). See :c:func:`mps_arena_commit_limit` for details. The
default commit limit is the maximum value of the
:c:type:`size_t` type.
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`,
default 8192) is the granularity with which the arena will
manage memory internally. It must be a power of 2, and at least
``sizeof(void *)``. Larger granularity reduces overheads, but
increases :term:`fragmentation` and :term:`retention`.
* :c:macro:`MPS_KEY_PAUSE_TIME` (type ``double``, default 0.1) is
the maximum time, in seconds, that operations within the arena
may pause the :term:`client program` for. See
:c:func:`mps_arena_pause_time_set` for details.
For example::
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, base);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
res = mps_arena_create_k(&arena, mps_arena_class_cl(), args);
} MPS_ARGS_END(args);
If the chunk is too small to hold the internal arena structures,
:c:func:`mps_arena_create_k` returns :c:macro:`MPS_RES_MEMORY`. In
this case, you need to use a (much) larger chunk.
.. note::
You don't have to provide all the memory up front: you can
call :c:func:`mps_arena_extend` later on.
Client arenas have no mechanism for returning unused memory.
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
Extend a :term:`client arena` with another block of memory.
``base`` is the :term:`address` of the block of memory that will be
managed by the arena.
``size`` is its :term:`size`.
Return :c:macro:`MPS_RES_OK` if successful, or another
:term:`result code` if it fails.
.. index::
single: arena class; virtual memory
single: virtual memory arena class
.. _topic-arena-vm:
Virtual memory arenas
---------------------
::
#include "mpsavm.h"
.. c:function:: mps_arena_class_t mps_arena_class_vm(void)
Return the :term:`arena class` for a :term:`virtual memory arena`.
A virtual memory arena uses the operating system's :term:`virtual
memory` interface to allocate memory. The chief consequence of
this is that the arena can manage many more virtual addresses than
it needs to commit memory to. This gives it flexibility as to
where to place :term:`blocks`, which reduces
:term:`fragmentation` and helps make :term:`garbage collection`
more efficient.
When creating a virtual memory arena, :c:func:`mps_arena_create_k`
accepts five optional :term:`keyword arguments` on all platforms:
* :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default
256 :term:`megabytes`) is the initial amount of virtual address
space, in :term:`bytes (1)`, that the arena will reserve (this
space is initially reserved so that the arena can subsequently
use it without interference from other parts of the program, but
most of it is not committed, so it doesn't require any RAM or
backing store). The arena may allocate more virtual address
space beyond this initial reservation as and when it deems it
necessary. The MPS is most efficient if you reserve an address
space that is several times larger than your peak memory usage.
If you specify a value for :c:macro:`MPS_KEY_ARENA_SIZE` that's
too small for the virtual memory arena, then the MPS rounds it
up to the minimum and continues. The minimum size for the
virtual memory arena is :c:macro:`MPS_WORD_WIDTH` ×
:c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` bytes. For example, on a
64-bit platform with a 4 :term:`kilobyte` page size, this is
256\ :term:`kilobytes`.
.. note::
The MPS asks for more address space if it runs out, but the
more times it has to extend its address space, the less
efficient garbage collection will become.
* :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of main memory, in :term:`bytes (1)`, that
the MPS will obtain from the operating system. See
:c:func:`mps_arena_commit_limit` for details. The default commit
limit is the maximum value of the :c:type:`size_t` type.
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`) is
the granularity with which the arena will manage memory
internally. It must be a power of 2. If not provided, the
operating system's page size is used. Larger granularity reduces
overheads, but increases :term:`fragmentation` and
:term:`retention`.
If you specify a value of :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE`
that's smaller than the operating system page size, the MPS
rounds it up to the page size and continues.
* :c:macro:`MPS_KEY_SPARE` (type ``double``, default 0.75) is the
maximum proportion of committed memory that the arena will keep
spare for future allocations. If the proportion of spare
committed memory exceeds this, then the arena will return some
of it to the operating system for use by other processes. See
:c:func:`mps_arena_spare` for details.
* :c:macro:`MPS_KEY_PAUSE_TIME` (type ``double``, default 0.1) is
the maximum time, in seconds, that operations within the arena
may pause the :term:`client program` for. See
:c:func:`mps_arena_pause_time_set` for details.
A sixth optional :term:`keyword argument` may be passed, but it
only has any effect on the Windows operating system:
* :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`,
default false). If true, the arena will allocate address space
starting at the highest possible address and working downwards
through memory.
.. note::
This causes the arena to pass the ``MEM_TOP_DOWN`` flag to
`VirtualAlloc`_.
.. _VirtualAlloc: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887%28v=vs.85%29.aspx
If the MPS fails to reserve adequate address space to place the
arena in, :c:func:`mps_arena_create_k` returns
:c:macro:`MPS_RES_RESOURCE`. Possibly this means that other parts
of the program are reserving too much virtual memory.
If the MPS fails to allocate memory for the internal arena
structures, :c:func:`mps_arena_create_k` returns
:c:macro:`MPS_RES_MEMORY`. Either :c:macro:`MPS_KEY_ARENA_SIZE`
was far too small or the operating system refused to provide
enough memory.
For example::
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
.. index::
single: arena; properties
Arena properties
----------------
.. c:function:: mps_word_t mps_collections(mps_arena_t arena)
Return the number of garbage collections (technically, the number
of :term:`flips`) in which objects might have moved, that have
taken place in an :term:`arena` since it was created.
``arena`` is the arena.
.. note::
If you are only using non-moving pool classes like
:ref:`pool-ams`, then :c:func:`mps_collections` will always
return 0. To find out about these collections, consider
enabling garbage collection messages: see
:c:func:`mps_message_type_gc`.
.. c:function:: size_t mps_arena_commit_limit(mps_arena_t arena)
Return the current :term:`commit limit` for
an arena.
``arena`` is the arena to return the commit limit for.
Returns the commit limit in :term:`bytes (1)`.
For a :term:`client arena`, this this the maximum amount of
memory, in :term:`bytes (1)`, that the MPS will use out of the
chunks provided by the client to the arena.
For a :term:`virtual memory arena`, this is the maximum amount of
memory that the MPS will map to RAM via the operating system's
virtual memory interface.
The commit limit can be set by passing the
:c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to
:c:func:`mps_arena_create_k`. It can be changed by calling
:c:func:`mps_arena_commit_limit_set`. The
commit limit cannot be set to a value that is lower than the
number of bytes that the MPS is using. If an attempt is made to
set the commit limit to a value greater than or equal to that
returned by :c:func:`mps_arena_committed` then it will succeed. If
an attempt is made to set the commit limit to a value less than
that returned by :c:func:`mps_arena_committed` then it will
succeed only if the amount committed by the MPS can be reduced by
reducing the amount of spare committed memory; in such a case the
spare committed memory will be reduced appropriately and the
attempt will succeed.
.. note::
The commit limit puts a limit on all memory committed by the
MPS. The :term:`spare committed memory` (that is, memory
committed by the MPS but not currently in use, neither by the
:term:`client program`, or by the MPS itself) can be limited
separately; see :c:func:`mps_arena_spare`. Note that "spare
committed" memory is subject to both limits; the proportion of
spare committed memory can't exceed the spare commit limit,
and there can't be so much spare committed memory that there
is more committed memory than the commit limit.
.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
Change the :term:`commit limit` for an :term:`arena`.
``arena`` is the arena to change the commit limit for.
``limit`` is the new commit limit in :term:`bytes (1)`.
Returns :c:macro:`MPS_RES_OK` if successful, or another
:term:`result code` if not.
To effectively remove any commit limit, pass the maximum value of
the :c:type:`size_t` type for the :c:data:`limit` argument, that
is, ``((size_t)-1)``, or :c:macro:`SIZE_MAX` in C99 or later.
See :c:func:`mps_arena_commit_limit` for details.
.. c:function:: size_t mps_arena_committed(mps_arena_t arena)
Return the total :term:`committed <mapped>` memory for an
:term:`arena`.
``arena`` is the arena.
Returns the total amount of memory that has been committed for use
by the MPS, in :term:`bytes (1)`.
For a :term:`virtual memory arena`, this is the amount of memory
mapped to RAM by the operating system's virtual memory interface.
For a :term:`client arena`, this is the amount of memory marked as
in use in the arena's page tables. This is not particularly
meaningful by itself, but it corresponds to the amount of mapped
memory that the MPS would use if switched to a virtual memory
arena.
The committed memory is generally larger than the sum of the sizes
of the allocated :term:`blocks`. The reasons for this are:
* some memory is used internally by the MPS to manage its own data
structures and to record information about allocated blocks
(such as free lists, page tables, colour tables, statistics, and
so on);
* operating systems (and hardware) typically restrict programs to
requesting and releasing memory with a certain granularity (for
example, :term:`pages`), so extra memory is committed
when this rounding is necessary;
* there might also be :term:`spare committed memory`: see
:c:func:`mps_arena_spare_committed`.
The amount of committed memory is a good measure of how much
virtual memory resource ("swap space") the MPS is using from the
operating system.
The function :c:func:`mps_arena_committed` may be called whatever
state the arena is in. If it is called when the arena is in
the :term:`unclamped state` then the value may change after this
function returns. A possible use might be to call it just after
:c:func:`mps_arena_collect` to estimate the size of the heap.
If you want to know how much memory the MPS is using then you're
probably interested in the value :c:func:`mps_arena_committed` −
:c:func:`mps_arena_spare_committed`.
The amount of committed memory can be limited with the function
:c:func:`mps_arena_commit_limit`.
.. c:function:: double mps_arena_pause_time(mps_arena_t arena)
Return the maximum time, in seconds, that operations within the
arena may pause the :term:`client program` for.
``arena`` is the arena.
See :c:func:`mps_arena_pause_time_set` for details.
.. c:function:: void mps_arena_pause_time_set(mps_arena_t arena, double pause_time)
Set the maximum time, in seconds, that operations within an arena
may pause the :term:`client program` for.
``arena`` is the arena.
``pause_time`` is the new maximum pause time, in seconds. It must
be non-negative.
The MPS makes more efficient use of processor time when it is
allowed longer pauses, up to the maximum time it takes to collect
the entire arena (see :c:func:`mps_arena_collect`).
When the pause time is short, the MPS needs to take more slices of
time in order to make :term:`garbage collection` progress, and
make more use of :term:`barriers (1)` to support
:term:`incremental garbage collection`. This increases time
overheads, and especially operating system overheads.
The pause time may be set to zero, in which case the MPS returns
as soon as it can, without regard for overall efficiency. This
value is suitable for applications that require high
responsiveness, but where overall run time is unimportant.
For interactive applications, set this to the longest pause that a
user won't notice. The default setting of 100ms is intended for
this kind of application.
The pause time may be set to infinity, in which case the MPS
completes all outstanding :term:`garbage collection` work before
returning from an operation. The consequence is that the MPS will
be able to save on the overheads due to :term:`incremental garbage
collection`, leading to lower total time spent in collection. This
value is suitable for non-interactive applications where total
time is important.
The MPS makes a best effort to return to the :term:`client
program` from any operation on the arena within the maximum pause
time, but does not guarantee to do so. This is for three reasons:
1. many operations in the MPS necessarily take some minimum amount
time that's logarithmic in the amount of :term:`memory (2)`
being managed (so if you set the maximum pause time to zero,
then every operation will exceed it);
2. some operations in the MPS call functions in the :term:`client
program` (for example, the :term:`format methods`), and the MPS
has no control over how long these functions take;
3. none of the operating systems supported by the MPS provide
real-time guarantees (for example, the process may have to wait
for :term:`memory (2)` to be :term:`paged in`).
In other words, the MPS is a “soft” real-time system.
.. c:function:: size_t mps_arena_reserved(mps_arena_t arena)
Return the total :term:`address space` reserved by an
:term:`arena`, in :term:`bytes (1)`.
``arena`` is the arena.
For a :term:`virtual memory arena`, this is the total address space
reserved via the operating system's virtual memory interface.
For a :term:`client arena`, this is the sum of the usable portions
of the chunks of memory passed to the arena by the :term:`client
program` via :c:func:`mps_arena_create_k` and
:c:func:`mps_arena_extend`.
.. note::
For a :term:`client arena`, the reserved address space may be
lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE`
keyword argument passed to :c:func:`mps_arena_create_k` and
the ``size`` arguments passed to :c:func:`mps_arena_extend`,
because the arena may be unable to use the whole of each chunk
for reasons of alignment.
.. c:function:: double mps_arena_spare(mps_arena_t arena)
Return the current :term:`spare commit limit` for an
:term:`arena`.
``arena`` is the arena to return the spare commit limit for.
Returns the spare commit limit fraction. The spare
commit limit is the maximum fraction of :term:`spare committed
memory` (that is, memory committed by the MPS but not currently in
use, neither by the :term:`client program`, or by the MPS itself)
the MPS is allowed to have.
For example, setting the :term:`spare commit limit` to 0.5 will
allow the arena to retain up to 50% of :term:`committed <mapped>`
memory as :term:`spare committed memory`.
The spare commit limit can be set by passing the
:c:macro:`MPS_KEY_SPARE` :term:`keyword argument` to
:c:func:`mps_arena_create_k`. It can be changed by calling
:c:func:`mps_arena_spare_set`. Setting it to a value lower than
the current fraction of spare committed memory causes spare
committed memory to be uncommitted so as to bring the value under
the limit. In particular, setting it to 0.0 will mean that the MPS
will have no spare committed memory.
.. c:function:: size_t mps_arena_spare_committed(mps_arena_t arena)
Return the total :term:`spare committed memory` for an
:term:`arena`.
``arena`` is the arena.
Returns the number of bytes of spare committed memory.
Spare committed memory is memory which the arena is managing as
free memory (not in use by any pool and not otherwise in use for
internal reasons) but which remains committed (mapped to RAM by
the operating system). It is used by the arena to (attempt to)
avoid calling the operating system to repeatedly map and unmap
areas of :term:`virtual memory` as the amount of memory in use
goes up and down. Spare committed memory is counted as committed
memory by :c:func:`mps_arena_committed` and is restricted by
:c:func:`mps_arena_commit_limit`.
The amount of "spare committed" memory can be limited passing the
:c:macro:`MPS_KEY_SPARE` :term:`keyword argument` to
:c:func:`mps_arena_create_k` or by calling
:c:func:`mps_arena_spare_set`. The value of the limit can be
retrieved with :c:func:`mps_arena_spare`. This is analogous to the
functions for limiting the amount of :term:`committed <mapped>`
memory.
.. note::
:term:`Client arenas` do not use spare committed memory, and
so this function always returns 0.
.. c:function:: void mps_arena_spare_set(mps_arena_t arena, double spare)
Change the :term:`spare commit limit` for an :term:`arena`.
``arena`` is the arena to change the spare commit limit for.
``spare`` is the new spare commit limit as a fraction of
:term:`committed <mapped>` memory. It must be between 0.0 and 1.0
inclusive.
Non-virtual-memory arena classes (for example, a :term:`client
arena`) do not have spare committed memory. For these arenas, this
function sets a value but has no other effect.
Initially the spare commit limit is a configuration-dependent
value. The value of the limit can be retrieved by the function
:c:func:`mps_arena_spare`.
.. index::
single: arena; states
Arena states
------------
An arena is always in one of four states.
#. .. index::
single: arena; unclamped state
single: unclamped state
In the *unclamped state*, garbage collection may take place,
objects may move in memory, references may be updated,
:term:`location dependencies` may become stale, virtual memory may
be requested from or returned to the operating system, and other
kinds of background activity may occur. This is the normal state.
#. .. index::
single: arena; clamped state
single: clamped state
In the *clamped state*, objects do not move in memory, references
do not change, the staleness of :term:`location dependencies` does
not change, and memory occupied by :term:`unreachable` objects is
not recycled.
However, a :term:`garbage collection` may be in progress and
incremental collection may still occur, but it will not be visible
to the :term:`client program` and no new collections will begin.
#. .. index::
single: arena; parked state
single: parked state
The *parked state* is the same as the clamped state, with the
additional constraint that no garbage collections are in progress.
#. .. index::
single: arena; postmortem state
single: postmortem state
In the *postmortem state*, incremental collection does not take
place, objects do not move in memory, references do not change, the
staleness of :term:`location dependencies` does not change, and
memory occupied by :term:`unreachable` objects is not recycled.
Additionally, all memory protection is removed, and memory may be
in an inconsistent state.
.. warning::
In this state, memory managed by the arena is not in a
consistent state, and so it is not safe to continue running the
client program. This state is intended for postmortem debugging
only.
Here's a summary:
============================================ ================================== ============================= =========================== ==============================
State unclamped clamped parked postmortem
============================================ ================================== ============================= =========================== ==============================
Collections may be running? yes yes no yes
New collections may start? yes no no no
Objects may move? yes no no no
Location dependencies may become stale? yes no no no
Memory may be returned to the OS? yes no no no
Safe to continue running? yes yes yes no
Functions that leave the arena in this state :c:func:`mps_arena_create_k`, :c:func:`mps_arena_clamp`, :c:func:`mps_arena_park`, :c:func:`mps_arena_postmortem`
:c:func:`mps_arena_release`, :c:func:`mps_arena_step` :c:func:`mps_arena_collect`
:c:func:`mps_arena_start_collect`,
:c:func:`mps_arena_step`
============================================ ================================== ============================= =========================== ==============================
The clamped and parked states are important when introspecting and
debugging. If you are examining the contents of the heap, you don't
want data moving under your feet. So for example, if your program is
stopped in GDB you might type::
(gdb) print mps_arena_clamp(arena)
before inspecting memory, and::
(gdb) print mps_arena_release(arena)
afterwards.
The results of introspection functions like
:c:func:`mps_arena_has_addr` only remain valid while the arena remains
in the parked state, and functions like :c:func:`mps_arena_roots_walk`
can only be called in this state.
.. c:function:: void mps_arena_clamp(mps_arena_t arena)
Put an :term:`arena` into the :term:`clamped state`.
``arena`` is the arena.
In the clamped state, no object motion will occur and the
staleness of :term:`location dependencies` will not change. All
references to objects loaded while the arena is clamped will keep
the same binary representation until after it is released by
calling :c:func:`mps_arena_release`.
In a clamped arena, incremental collection may still occur, but it
will not be visible to the mutator and no new collections will
begin. Space used by unreachable objects will not be recycled
until the arena is unclamped.
.. c:function:: void mps_arena_park(mps_arena_t arena)
Put an :term:`arena` into the :term:`parked state`.
``arena`` is the arena.
While an arena is parked, no object motion will occur and the
staleness of :term:`location dependencies` will not change. All
references to objects loaded while the arena is parked will keep
the same binary representation until after it is released.
Any current collection is run to completion before the arena is
parked, and no new collections will start. When an arena is in the
parked state, it is necessarily not in the middle of a collection.
.. c:function:: void mps_arena_release(mps_arena_t arena)
Put an arena into the :term:`unclamped state`.
``arena`` is the arena.
While an arena is unclamped, :term:`garbage collection`, object
motion, and other background activity can take place.
.. c:function:: void mps_arena_postmortem(mps_arena_t arena)
Put an arena into the :term:`postmortem state`.
``arena`` is the arena.
In the postmortem state, incremental collection does not take
place, objects do not move in memory, references do not change,
the staleness of :term:`location dependencies` does not change,
and memory occupied by :term:`unreachable` objects is not
recycled. Additionally, all memory protection is removed, and
memory may be in an inconsistent state.
.. warning::
1. After calling this function, memory managed by the arena is
not in a consistent state, and so it is no longer safe to
continue running the client program. This function is
intended for postmortem debugging only.
2. This function must be called from the thread that holds the
arena lock (if any thread holds it). This is the case if the
program is single-threaded, or if it is called from an MPS
assertion handler. When calling this function from the
debugger, check the stack to see which thread has the MPS
arena lock.
.. index::
single: garbage collection; running
single: collection; running
Running garbage collections
---------------------------
The Memory Pool System's garbage collector runs :term:`asynchronously
<asynchronous garbage collector>` and :term:`incrementally
<incremental garbage collection>`. This means that it is not normally
necessary to tell it when to start garbage collections, or to wait
until it has finished collecting. (But if your program has idle time
that could be productively spent by the MPS, see
:ref:`topic-arena-idle` below.)
However, during development and testing it is useful to be able to
request that MPS run a full :term:`collection cycle`. For example, you
might run frequent collections in an attempt to detect bugs in your
allocation and scanning code.
.. c:function:: void mps_arena_collect(mps_arena_t arena)
Collect an arena and put it into the :term:`parked state`.
``arena`` is the arena to collect.
The collector attempts to recycle as many unreachable objects as
possible and reduce the size of the arena as much as possible
(though in some cases it may increase because it becomes more
fragmented). Note that the collector may not be able to recycle
some objects (such as those near the destination of ambiguous
references) even though they are not reachable.
If you do not want the arena to remain in the parked state, you
must explicitly call :c:func:`mps_arena_release` afterwards.
.. note::
It is not normally necessary to call this function: in the
:term:`unclamped state`, collections start automatically.
However, it may be useful during development and debugging:
the more frequently the collector runs, the sooner and more
reliably errors are discovered. See :ref:`guide-debug-advice`.
.. c:function:: mps_res_t mps_arena_start_collect(mps_arena_t arena)
Request an :term:`arena` to start a full :term:`collection cycle`.
``arena`` is the arena.
Returns :c:macro:`MPS_RES_OK` if a collection is started, or
another :term:`result code` if not.
This function puts ``arena`` into the :term:`unclamped state` and
requests that it start a full collection cycle. The call to
:c:func:`mps_arena_start_collect` returns quickly, leaving the
collection to proceed incrementally (as for a collection that is
scheduled automatically).
.. note::
Contrast with :c:func:`mps_arena_collect`, which does not
return until the collection has completed.
.. index::
single: garbage collection; limiting pause
single: garbage collection; using idle time
single: idle time; using for garbage collection
single: pause; limiting
.. _topic-arena-idle:
Using idle time for collection
------------------------------
Some types of program have "idle time" in which they are waiting for
an external event such as user input or network activity. The MPS
provides a function, :c:func:`mps_arena_step`, for making use of idle
time to make memory management progress.
Here's an example illustrating the use of this function in a program's
event loop. ::
for (;;) { /* event loop */
for (;;) {
if (client_is_waiting()) {
perform_client_action();
} else if (!mps_arena_step(arena, 0.010, 0.0)) {
/* no incremental MPS work remaining */
break;
}
}
if (!block_on_client_with_timeout(2.0)) {
/* Perhaps the user has gone for a cup of coffee? Allow the
* MPS to start a big piece of work, but don't actually pause
* for more than 10 ms. */
mps_arena_step(arena, 0.010, 100.0);
}
}
When the program is idle (there are no client actions to perform), it
requests that the MPS spend up to 10 milliseconds on incremental work,
by calling ``mps_arena_step(arena, 0.010, 0.0)``. When this returns
false to indicate that there is no more work to do, the program blocks
on the client for two seconds: if this times out, it predicts that the
user will remain idle for at least a further second, so it calls
``mps_arena_step(arena, 0.010, 100.0)`` to tell that it's a good time
to start a collection taking up to 10 ms × 100 = 1 second, but not to
pause for more than 10 ms.
The program remains responsive: the MPS doesn't take control for more
than a few milliseconds at a time (at most 10). But at the same time,
major collection work can get done at times when the program would
otherwise be idle. Of course the numbers here are only for
illustration; they should be chosen based on the requirements of the
application.
.. c:function:: mps_bool_t mps_arena_step(mps_arena_t arena, double interval, double multiplier)
Request an :term:`arena` to do some work during a period where the
:term:`client program` is idle.
``arena`` is the arena.
``interval`` is the time, in seconds, the MPS is permitted to
take. It must not be negative, but may be ``0.0``.
``multiplier`` is the number of further similar calls that the
client program expects to make during this idle period.
Returns true if there was work for the MPS to do in ``arena``
(regardless of whether or not it did any) or false if there was
nothing to do.
:c:func:`mps_arena_step` allows the client program to make use of
idle time to do some garbage collection, for example when it is
waiting for interactive input. The MPS makes every effort to
return from this function within ``interval`` seconds, but cannot
guarantee to do so, as it may need to call your own scanning
code. It uses ``multiplier`` to decide whether to commence
long-duration operations that consume CPU (such as a full
collection): it will only start such an operation if it is
expected to be completed within ``multiplier * interval`` seconds.
If the arena was in the :term:`parked state` or the :term:`clamped
state` before :c:func:`mps_arena_step` was called, it is in the
clamped state afterwards. It it was in the :term:`unclamped
state`, it remains there.
.. index::
pair: arena; introspection
pair: arena; debugging
Arena introspection and debugging
---------------------------------
.. note::
Introspection functions covered in other chapters are:
* :c:func:`mps_addr_fmt`: determine the :term:`object format` to
which an address belongs;
* :c:func:`mps_pool_walk`: visit all areas of :term:`formatted
objects` in a :term:`pool`;
* :c:func:`mps_arena_roots_walk`: visit all references in
:term:`roots` registered with an arena; and
* :c:func:`mps_addr_pool`: determine the :term:`pool` to which an
address belongs.
.. c:function:: mps_bool_t mps_arena_busy(mps_arena_t arena)
Return true if an :term:`arena` is part of the way through
execution of an operation, false otherwise.
``arena`` is the arena.
.. note::
This function is intended to assist with debugging fatal
errors in the :term:`client program`. It is not expected to be
needed in normal use. If you find yourself wanting to use this
function other than in the use case described below, there may
be a better way to meet your requirements: please
:ref:`contact us <contact>`.
A debugger running on Windows on x86-64 needs to decode the
call stack, which it does by calling a callback that was
previously installed in the dynamic function table using
|RtlInstallFunctionTableCallback|_. If the debugger is entered
while the arena is busy, and if the callback needs to read
from MPS-managed memory, then it may attempt to re-enter the
MPS, which will fail as the MPS is not re-entrant.
.. |RtlInstallFunctionTableCallback| replace:: ``RtlInstallFunctionTableCallback()``
.. _RtlInstallFunctionTableCallback: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680595(v=vs.85).aspx
If this happens, in order to allow the debugger to finish
decoding the call stack, the only remedy is to put the arena
into the :term:`postmortem state`, so that memory is
:term:`unprotected` and objects do not move. So in your
dynamic function table callback, you might write::
if (mps_arena_busy(arena)) {
mps_arena_postmortem(arena);
}
.. warning::
This function only gives a reliable result in single-threaded
programs, and in multi-threaded programs where all threads but
one are known to be stopped (as they are when the debugger is
decoding the call stack in the use case described above).
.. c:function:: mps_bool_t mps_arena_has_addr(mps_arena_t arena, mps_addr_t addr)
Test whether an :term:`address` is managed by an :term:`arena`.
``arena`` is an arena.
``addr`` is an address.
Returns true if ``addr`` is managed by ``arena``; false otherwise.
An arena manages a portion of :term:`address space`. No two arenas
overlap, so for any particular address this function will return
true for at most one arena.
In general, not all addresses are managed by any arena. This is
what allows the MPS to cooperate with other memory managers,
shared object loaders, memory mapped file input/output, and so on:
it does not steal the whole address space.
.. note::
The result from this function is valid only at the instant at
which the function returned. In some circumstances the result
may immediately become invalidated (for example, a
:term:`garbage collection` may occur, the address in question
may become free, the arena may choose to unmap the address and
return storage to the operating system). For reliable results
call this function and interpret the result while the arena is
in the :term:`parked state`.
.. seealso::
To find out which :term:`pool` the address belongs to, use
:c:func:`mps_addr_pool`, and to find out which :term:`object
format` describes the object at the address, use
:c:func:`mps_addr_fmt`.
.. c:function:: mps_res_t mps_addr_object(mps_addr_t *p_o, mps_arena_t arena, mps_addr_t addr)
Find the :term:`base pointer` of an :term:`object` if provided with an
:term:`interior pointer` to that object, or the object's base pointer,
provided the object exists in a pool that supports this feature.
``p_o`` points to a location that will hold the object's base pointer.
``arena`` is an arena.
``addr`` is an address that might be an interior or base pointer.
Returns MPS_RES_OK if a base pointer to an object into which ``addr``
points was successfully returned.
Returns MPS_RES_FAIL if ``addr`` points to memory not managed by the
``arena`` or if ``addr`` points to the interior of an object which has
been moved by a :term:`moving memory manager`.
Returns MPS_RES_UNIMPL if ``addr`` is found to be managed by a :term:`pool`
which does not currently implement this feature.
:c:func:`mps_addr_object` allows client programs that allocate
code on the heap to implement debugging and stack tracing, in that it provides
a way to unwind a client program's stack by finding the block of code to which the
program counter or function return addresses currently point. It can be called
multiple times as needed to build a complete trace of the client program's stack.
This function does not support debugging in situations where the arena
itself has encountered a runtime error. For cases where the MPS encounters
runtime errors, see :c:func:`mps_arena_postmortem`.
.. note::
This function is intended to assist with debugging fatal
errors in the :term:`client program`. It is not expected to be
needed in normal use, i.e. as part of the regular operation of code in
production, since it is not optimized for performance. If you find yourself
wanting to use this function other than in the use case described, there may
be a better way to meet your requirements: please
:ref:`contact us <contact>`.
If you would like this function to work in a pool in which it's currently
unimplemented, please :ref:`contact us <contact>`.
|