50
50
timeout ,
51
51
timer ,
52
52
alarmed ,
53
- alarm_funs
54
- }).
53
+ alarm_funs ,
54
+ os_type = undefined ,
55
+ os_pid = undefined ,
56
+ page_size = undefined ,
57
+ proc_file = undefined }).
55
58
56
59
-include (" rabbit_memory.hrl" ).
57
60
@@ -130,86 +133,38 @@ get_memory_use(ratio) ->
130
133
% % be equal to the total size of all pages mapped to the emulator,
131
134
% % according to http://erlang.org/doc/man/erlang.html#memory-0
132
135
% % erlang:memory(total) under-reports memory usage by around 20%
136
+ % %
137
+ % % Win32 Note: 3.6.12 shipped with code that used wmic.exe to get the
138
+ % % WorkingSetSize value for the running erl.exe process. Unfortunately
139
+ % % even with a moderate invocation rate of 1 ops/second that uses more
140
+ % % CPU resources than some Windows users are willing to tolerate.
141
+ % % See rabbitmq/rabbitmq-server#1343 and rabbitmq/rabbitmq-common#224
142
+ % % for details.
133
143
-spec get_process_memory () -> Bytes :: integer ().
134
144
get_process_memory () ->
135
- case get_memory_calculation_strategy () of
136
- rss ->
137
- case get_system_process_resident_memory () of
138
- {ok , MemInBytes } ->
139
- MemInBytes ;
140
- {error , Reason } ->
141
- rabbit_log :debug (" Unable to get system memory used. Reason: ~p ."
142
- " Falling back to erlang memory reporting" ,
143
- [Reason ]),
144
- erlang :memory (total )
145
- end ;
146
- erlang ->
147
- erlang :memory (total )
145
+ try
146
+ {ProcMem , _ } = get_memory_use (bytes ),
147
+ ProcMem
148
+ catch exit :{noproc , Error } ->
149
+ rabbit_log :warning (" Memory monitor process not yet started: ~p~n " , [Error ]),
150
+ get_process_memory_uncached ()
148
151
end .
149
152
150
153
-spec get_memory_calculation_strategy () -> rss | erlang .
151
154
get_memory_calculation_strategy () ->
152
- case rabbit_misc :get_env (rabbit , vm_memory_calculation_strategy , rss ) of
153
- erlang ->
154
- erlang ;
155
- rss ->
156
- rss ;
155
+ case rabbit_misc :get_env (rabbit , vm_memory_calculation_strategy , allocated ) of
156
+ allocated -> allocated ;
157
+ erlang -> erlang ;
158
+ legacy -> erlang ; % % backwards compatibility
159
+ rss -> rss ;
157
160
UnsupportedValue ->
158
161
rabbit_log :warning (
159
162
" Unsupported value '~p ' for vm_memory_calculation_strategy. "
160
- " Supported values: (rss |erlang). "
161
- " Defaulting to 'rss '" ,
163
+ " Supported values: (allocated |erlang|legacy|rss ). "
164
+ " Defaulting to 'allocated '" ,
162
165
[UnsupportedValue ]
163
166
),
164
- rss
165
- end .
166
-
167
- -spec get_system_process_resident_memory () -> {ok , Bytes :: integer ()} | {error , term ()}.
168
- get_system_process_resident_memory () ->
169
- try
170
- get_system_process_resident_memory (os :type ())
171
- catch _ :Error ->
172
- {error , {" Failed to get process resident memory" , Error }}
173
- end .
174
-
175
- get_system_process_resident_memory ({unix ,darwin }) ->
176
- get_ps_memory ();
177
-
178
- get_system_process_resident_memory ({unix , linux }) ->
179
- get_ps_memory ();
180
-
181
- get_system_process_resident_memory ({unix ,freebsd }) ->
182
- get_ps_memory ();
183
-
184
- get_system_process_resident_memory ({unix ,openbsd }) ->
185
- get_ps_memory ();
186
-
187
- get_system_process_resident_memory ({win32 ,_OSname }) ->
188
- % % Note: 3.6.12 shipped with code that used wmic.exe to get the
189
- % % WorkingSetSize value for the running erl.exe process. Unfortunately
190
- % % even with a moderate invocation rate of 1 ops/second that uses more
191
- % % CPU resources than some Windows users are willing to tolerate.
192
- % % See rabbitmq/rabbitmq-server#1343 for details.
193
- {ok , erlang :memory (total )};
194
-
195
- get_system_process_resident_memory ({unix , sunos }) ->
196
- get_ps_memory ();
197
-
198
- get_system_process_resident_memory ({unix , aix }) ->
199
- get_ps_memory ();
200
-
201
- get_system_process_resident_memory (_OsType ) ->
202
- {error , not_implemented_for_os }.
203
-
204
- get_ps_memory () ->
205
- OsPid = os :getpid (),
206
- Cmd = " ps -p " ++ OsPid ++ " -o rss=" ,
207
- CmdOutput = os :cmd (Cmd ),
208
- case re :run (CmdOutput , " [0-9]+" , [{capture , first , list }]) of
209
- {match , [Match ]} ->
210
- {ok , list_to_integer (Match ) * 1024 };
211
- _ ->
212
- {error , {unexpected_output_from_command , Cmd , CmdOutput }}
167
+ allocated
213
168
end .
214
169
215
170
% %----------------------------------------------------------------------------
@@ -226,11 +181,12 @@ start_link(MemFraction, AlarmSet, AlarmClear) ->
226
181
227
182
init ([MemFraction , AlarmFuns ]) ->
228
183
TRef = erlang :send_after (? DEFAULT_MEMORY_CHECK_INTERVAL , self (), update ),
229
- State = # state { timeout = ? DEFAULT_MEMORY_CHECK_INTERVAL ,
230
- timer = TRef ,
231
- alarmed = false ,
232
- alarm_funs = AlarmFuns },
233
- {ok , set_mem_limits (State , MemFraction )}.
184
+ State0 = # state {timeout = ? DEFAULT_MEMORY_CHECK_INTERVAL ,
185
+ timer = TRef ,
186
+ alarmed = false ,
187
+ alarm_funs = AlarmFuns },
188
+ State1 = init_state_by_os (State0 ),
189
+ {ok , set_mem_limits (State1 , MemFraction )}.
234
190
235
191
handle_call (get_vm_memory_high_watermark , _From ,
236
192
# state {memory_config_limit = MemLimit } = State ) ->
@@ -282,6 +238,53 @@ code_change(_OldVsn, State, _Extra) ->
282
238
% %----------------------------------------------------------------------------
283
239
% % Server Internals
284
240
% %----------------------------------------------------------------------------
241
+
242
+ get_process_memory_uncached () ->
243
+ TmpState = init_state_by_os (# state {}),
244
+ TmpState # state .process_memory .
245
+
246
+ update_process_memory (State ) ->
247
+ Strategy = get_memory_calculation_strategy (),
248
+ {ok , ProcMem } = get_process_memory_using_strategy (Strategy , State ),
249
+ State # state {process_memory = ProcMem }.
250
+
251
+ init_state_by_os (State = # state {os_type = undefined }) ->
252
+ OsType = os :type (),
253
+ OsPid = os :getpid (),
254
+ init_state_by_os (State # state {os_type = OsType , os_pid = OsPid });
255
+ init_state_by_os (State0 = # state {os_type = {unix , linux }, os_pid = OsPid }) ->
256
+ PageSize = get_linux_pagesize (),
257
+ ProcFile = io_lib :format (" /proc/~s /statm" , [OsPid ]),
258
+ State1 = State0 # state {page_size = PageSize , proc_file = ProcFile },
259
+ update_process_memory (State1 );
260
+ init_state_by_os (State ) ->
261
+ update_process_memory (State ).
262
+
263
+ get_process_memory_using_strategy (rss , # state {os_type = {unix , linux },
264
+ page_size = PageSize ,
265
+ proc_file = ProcFile }) ->
266
+ Data = read_proc_file (ProcFile ),
267
+ [_ |[RssPagesStr |_ ]] = string :split (Data , " " , all ),
268
+ ProcMem = list_to_integer (RssPagesStr ) * PageSize ,
269
+ {ok , ProcMem };
270
+ get_process_memory_using_strategy (rss , # state {os_type = {unix , _ },
271
+ os_pid = OsPid }) ->
272
+ Cmd = " ps -p " ++ OsPid ++ " -o rss=" ,
273
+ CmdOutput = os :cmd (Cmd ),
274
+ case re :run (CmdOutput , " [0-9]+" , [{capture , first , list }]) of
275
+ {match , [Match ]} ->
276
+ ProcMem = list_to_integer (Match ) * 1024 ,
277
+ {ok , ProcMem };
278
+ _ ->
279
+ {error , {unexpected_output_from_command , Cmd , CmdOutput }}
280
+ end ;
281
+ get_process_memory_using_strategy (rss , _State ) ->
282
+ {ok , recon_alloc :memory (allocated )};
283
+ get_process_memory_using_strategy (allocated , _State ) ->
284
+ {ok , recon_alloc :memory (allocated )};
285
+ get_process_memory_using_strategy (erlang , _State ) ->
286
+ {ok , erlang :memory (total )}.
287
+
285
288
get_total_memory_from_os () ->
286
289
try
287
290
get_total_memory (os :type ())
@@ -374,19 +377,20 @@ parse_mem_limit(MemLimit) ->
374
377
),
375
378
? DEFAULT_VM_MEMORY_HIGH_WATERMARK .
376
379
377
- internal_update (State = # state { memory_limit = MemLimit ,
378
- alarmed = Alarmed ,
379
- alarm_funs = {AlarmSet , AlarmClear } }) ->
380
- ProcMem = get_process_memory (),
381
- NewAlarmed = ProcMem > MemLimit ,
380
+ internal_update (State0 = # state {memory_limit = MemLimit ,
381
+ alarmed = Alarmed ,
382
+ alarm_funs = {AlarmSet , AlarmClear }}) ->
383
+ State1 = update_process_memory (State0 ),
384
+ ProcMem = State1 # state .process_memory ,
385
+ NewAlarmed = ProcMem > MemLimit ,
382
386
case {Alarmed , NewAlarmed } of
383
387
{false , true } -> emit_update_info (set , ProcMem , MemLimit ),
384
388
AlarmSet ({{resource_limit , memory , node ()}, []});
385
389
{true , false } -> emit_update_info (clear , ProcMem , MemLimit ),
386
390
AlarmClear ({resource_limit , memory , node ()});
387
391
_ -> ok
388
392
end ,
389
- State # state {alarmed = NewAlarmed , process_memory = ProcMem }.
393
+ State1 # state {alarmed = NewAlarmed }.
390
394
391
395
emit_update_info (AlarmState , MemUsed , MemLimit ) ->
392
396
rabbit_log :info (
@@ -420,22 +424,33 @@ cmd(Command) ->
420
424
_ -> os :cmd (Command )
421
425
end .
422
426
427
+ get_linux_pagesize () ->
428
+ CmdOutput = cmd (" getconf PAGESIZE" ),
429
+ case re :run (CmdOutput , " ^[0-9]+" , [{capture , first , list }]) of
430
+ {match , [Match ]} -> list_to_integer (Match );
431
+ _ ->
432
+ rabbit_log :warning (
433
+ " Failed to get memory page size, using 4096:~n~p~n " ,
434
+ [CmdOutput ]),
435
+ 4096
436
+ end .
437
+
423
438
% % get_total_memory(OS) -> Total
424
439
% % Windows and Freebsd code based on: memsup:get_memory_usage/1
425
440
% % Original code was part of OTP and released under "Erlang Public License".
426
441
427
- get_total_memory ({unix ,darwin }) ->
442
+ get_total_memory ({unix , darwin }) ->
428
443
sysctl (" hw.memsize" );
429
444
430
- get_total_memory ({unix ,freebsd }) ->
445
+ get_total_memory ({unix , freebsd }) ->
431
446
PageSize = sysctl (" vm.stats.vm.v_page_size" ),
432
447
PageCount = sysctl (" vm.stats.vm.v_page_count" ),
433
448
PageCount * PageSize ;
434
449
435
- get_total_memory ({unix ,openbsd }) ->
450
+ get_total_memory ({unix , openbsd }) ->
436
451
sysctl (" hw.usermem" );
437
452
438
- get_total_memory ({win32 ,_OSname }) ->
453
+ get_total_memory ({win32 , _OSname }) ->
439
454
[Result |_ ] = os_mon_sysinfo :get_mem_info (),
440
455
{ok , [_MemLoad , TotPhys , _AvailPhys , _TotPage , _AvailPage , _TotV , _AvailV ],
441
456
_RestStr } =
0 commit comments