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
.. 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`.