-module(gc_simulation).
-compile(export_all).
-record(memory_data, {
heap_stack = 0,
heap = 0,
stack = 0,
high_water = 0,
old_heap = 0,
old_heap_max = 0,
%% 标记过期数据
heap_garbage = 0
}).
heap_size() ->
ListA = lists:foldl(fun(_, [H1, H2|Acc]) ->
[H1+H2+1,H1,H2|Acc]
end, [38,12], lists:seq(2,22,1)),
ListB = lists:foldl(fun(_, [H1|Acc]) ->
[H1+H1 div 5,H1|Acc]
end, ListA, lists:seq(1,20,1)),
lists:reverse(ListB).
memory_data_init(All, Heap, Stack, OldHeap, OldMax) ->
#memory_data{
heap_stack = All,
heap = Heap,
stack = Stack,
old_heap = OldHeap,
old_heap_max = OldMax
}.
garbage_mark(heap, Size, MemData) ->
MemData#memory_data{heap_garbage = Size + MemData#memory_data.heap_garbage}.
%% 申请空间
need_heap(Need, #memory_data{heap = HeapUsed, stack = StackUsed, heap_stack = All} = MemData) when HeapUsed+StackUsed+Need > All ->
need_heap(Need, garbage__collect(Need, MemData));
need_heap(Need, #memory_data{heap = HeapUsed} = MemData) ->
MemData#memory_data{heap = HeapUsed + Need}.
need_stack(Need, #memory_data{heap = HeapUsed, stack = StackUsed, heap_stack = All} = MemData) when HeapUsed+StackUsed+Need > All ->
need_stack(Need, garbage__collect(Need, MemData));
need_stack(Need, #memory_data{stack = StackUsed} = MemData) ->
MemData#memory_data{stack = StackUsed + Need}.
%% 释放空间
free_heap(FreeNum, MemData) ->
MemData#memory_data{heap = MemData#memory_data.heap - FreeNum}.
free_stack(FreeNum, MemData) ->
MemData#memory_data{stack = MemData#memory_data.stack - FreeNum}.
%% gc模拟 --不考虑小gc次数达到max_gen_gcs次数时触发的大gc情况
garbage__collect(Need, MemData) ->
io:format("minor_collection start:~p~n",[MemData]),
case minor_collection(Need, MemData) of
{-1, MemData1} ->
io:format("minor_collection end:~p~n",[MemData1]),
io:format("major_collection start:~p~n",[MemData1]),
MemData2 = major_collection(Need, MemData1),
io:format("major_collection end:~p~n",[MemData2]),
MemData2;
MemData1 ->
io:format("minor_collection end:~p~n",[MemData1]),
MemData1
end.
minor_collection(Need, #memory_data{
heap = HeapUsed,
high_water = HighWater,
old_heap_max = OldMax
} = MemData) when OldMax =:= 0 andalso HighWater =/= 0 ->
minor_collection(Need, MemData#memory_data{old_heap_max = next_heap_size(HeapUsed, 1)});
minor_collection(Need, #memory_data{
heap = HeapUsed,
stack = StackUsed,
high_water = HighWater,
old_heap = OldHeap,
old_heap_max = OldMax
} = MemData) when OldMax =/= 0 andalso HighWater =< OldMax - OldHeap ->
%% 老堆空间够存放水位线下的数据时,进行小gc
MemData1 = do_minor(next_heap_size(StackUsed + HeapUsed, 0), MemData),
NeedAfter = MemData1#memory_data.heap + MemData1#memory_data.stack + Need,
NowHeapSize = MemData1#memory_data.heap_stack,
case NowHeapSize > 3000 andalso 4 * NeedAfter < NowHeapSize
andalso (NowHeapSize > 8000 orelse NowHeapSize > MemData1#memory_data.old_heap) of
true ->
%% gc后剩余空间过多,则缩小空间
Wanted = 3 * NeedAfter,
Wanted1 = case Wanted*9 < MemData1#memory_data.old_heap_max of
true ->
Temp = MemData1#memory_data.old_heap_max div 8,
case Temp > Wanted of
true -> Temp;
_ -> Wanted
end;
_ ->
Wanted
end,
shrink_heap(MemData1, next_heap_size(Wanted1, 0));
_ ->
case NeedAfter > NowHeapSize of
true ->
%% gc后剩余空间不够,则增长空间
grow_heap(MemData1, next_heap_size(NeedAfter, 0));
_ ->
MemData1
end
end;
minor_collection(_, MemData) -> {-1, MemData}.
major_collection(Need, #memory_data{
heap = HeapUsed,
stack = StackUsed,
heap_garbage = HeapGar,
old_heap = OldHeap
} = MemData) ->
NewSize = next_heap_size(HeapUsed + StackUsed + OldHeap, 0),
MemData1 = MemData#memory_data{
heap_stack = NewSize,
heap = HeapUsed+OldHeap-HeapGar,
high_water = HeapUsed+OldHeap-HeapGar,
old_heap = 0,
old_heap_max = 0
},
adjust_after_fullsweep(Need, MemData1).
adjust_after_fullsweep(Need, #memory_data{
heap_stack = All
} = MemData) ->
NeedAfter = MemData#memory_data.heap + MemData#memory_data.stack + Need,
case All < NeedAfter of
true ->
Size = next_heap_size(NeedAfter, 0),
grow_heap(MemData, Size);
_ ->
case 3 * All < 4 * NeedAfter of
true ->
grow_heap(MemData, next_heap_size(NeedAfter, 0));
_ ->
case 4 * NeedAfter < All of
true ->
Wanted = next_heap_size(2 * NeedAfter, 0),
shrink_heap(MemData, Wanted);
_ ->
MemData
end
end
end.
do_minor(NewSize, #memory_data{
heap = HeapUsed,
high_water = HighWater,
heap_garbage = HeapGar,
old_heap = OldHeap
} = MemData) ->
MemData#memory_data{
heap_stack = NewSize,
heap = HeapUsed-HighWater-HeapGar,
high_water = HeapUsed-HighWater-HeapGar,
heap_garbage = 0,
old_heap = OldHeap+HighWater
}.
next_heap_size(Size, OffSet) ->
HeapSize = heap_size(),
{_, NextSize} = lists:foldl(fun
(_, {[H1, H2|Acc], 0}) when OffSet =:= 1 andalso H1 >= Size -> {[H2|Acc], H2};
(_, {[H1|Acc], 0}) when OffSet =:= 0 andalso H1 >= Size -> {Acc, H1};
(_, {[_|Acc], Ans}) -> {Acc, Ans}
end, {HeapSize, 0}, lists:seq(1, length(HeapSize), 1)),
NextSize.
grow_heap(MemData, TargetMem) ->
MemData#memory_data{heap_stack = TargetMem}.
shrink_heap(MemData, TargetMem) ->
MemData#memory_data{heap_stack = TargetMem}.
模拟代码示例:
-module(gc_test).
-compile(export_all).
tail_test() ->
MemData = gc_simulation:memory_data_init(233,0,0,0,0),
MemData1 = lists:foldl(fun(_, OldMemData) ->
gc_simulation:need_heap(8, OldMemData)
end, MemData, lists:seq(1,20000 div 8,1)),
lists:foldl(fun(_, OldMemData) ->
Temp = gc_simulation:need_stack(4, OldMemData),
Temp1 = gc_simulation:need_heap(2, Temp),
gc_simulation:free_stack(4, Temp1)
end, MemData1, lists:seq(1,10000,1)).
body_test() ->
MemData = gc_simulation:memory_data_init(233,0,0,0,0),
MemData1 = lists:foldl(fun(_, OldMemData) ->
gc_simulation:need_heap(8, OldMemData)
end, MemData, lists:seq(1,20000 div 8,1)),
MemData2 = lists:foldl(fun(_, OldMemData) ->
Temp = gc_simulation:need_stack(3, OldMemData),
gc_simulation:free_stack(1, Temp)
end, MemData1, lists:seq(1,10000,1)),
lists:foldl(fun(_, OldMemData) ->
Temp = gc_simulation:need_heap(2, OldMemData),
gc_simulation:free_stack(2, Temp)
end, MemData2, lists:seq(1,10000,1)).