Поддержание значения OCaml навсегда вне кучи / намеренная утечка значения OCaml - PullRequest
0 голосов
/ 06 июня 2018

Что нужно сделать, чтобы выделить бессмертный объект OCaml вне кучи в функции C?В частности, как сделать значение OCaml, которое выглядит во время выполнения как глобальная переменная в исходном коде OCaml.

Вот моя попытка создать намеренно неработающую программу, которая не регистрирует значение как GCroot.

Вот исходный файл OCaml, управляющий всем.

(* immortal_string.ml *)

external make_string : string -> unit = "make_string"
external get_string : unit -> string = "get_string"

let () = make_string "a"
let () = Gc.full_major ()
let () = Printf.printf "%s\n" (get_string ())

И реализация C.Вероятно, есть лучшие способы сделать это, чем использовать 0 в качестве значения часового и статической функции, но я думаю, что цель ясна.Обратите внимание, что множественные вызовы make_string приведут к значению, которое изначально было там, но это нормально.Я хочу, чтобы память, на которую ссылались старые значения, была возвращена сборщиком мусора.

// lib_immortal_string.c

#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>

value *storage(void) {
    // BAD! we haven't registered this thing
    // as a GC root. No clue how you do that.
    static value data = 0; // sentinel, will never be valid OCaml value
    if (data == 0) {
        data = caml_copy_string("");
    }
    return &data;
}

CAMLprim value
make_string(value ml_string) {
    CAMLparam1(ml_string);
    *storage() = ml_string;
    CAMLreturn(Val_unit);
}

CAMLprim value
get_string(value ml_unit) {
    CAMLparam1(ml_unit);
    CAMLreturn(*storage());
}

Я ожидал, что эта программа перестанет работать, так как нет ничего очевидного в том, что data в функции storage в действии.data не является глобальным и не находится в стеке.Тем не менее, программа , по-видимому, запускается без восстановления строки.

$ ocamlopt immortal_string.ml lib_immortal_string.c
./a.out
a

Итак, мой вопрос: как правильно сделать глобальное значение OCaml / вне кучи?И, кроме того, почему вышеуказанная программа работает, а не падает?

1 Ответ

0 голосов
/ 06 июня 2018

Практически нет повторного использования памяти в вашей маленькой программе, поэтому я предполагаю, что строка "a" по-прежнему выглядит так же после сборки мусора, даже если на нее ничего не ссылается.

Если вы вызываетеGC каждый раз просто возвращает вещи в упорядоченное состояние.Было бы лучше, чтобы GC происходил нормально, что будет проходить через много других возможных состояний памяти.

Вам также нужно сделать цикл, чтобы дать ему время на сбой.

Слегка измененныйверсия вашего кода на самом деле делает для меня segfault:

external make_string : string -> unit = "make_string"
external get_string : unit -> string = "get_string"

let () =
    while true do
        let a = String.make (1024 * 1024) 'a' in
        make_string a;
        let b = String.make (1024 * 1024) 'b' in
        Printf.printf "%s %s\n" (get_string ()) b
    done

Способ пометить значение как корень GC можно с помощью caml_register_global_root

caml_register_global_root(&data);

Так же, как вы ожидали, еслиЯ называю это под if (data == 0) {, здесь нет ошибки.

Это задокументировано в Разделе 19.5 руководства OCaml .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...