erlang gc模拟器——直观理解gc规则

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值