@@ -53,6 +53,9 @@ const kClearEntry = Symbol('clear-entry');
53
53
const kGetEntries = Symbol ( 'get-entries' ) ;
54
54
const kIndex = Symbol ( 'index' ) ;
55
55
const kMarks = Symbol ( 'marks' ) ;
56
+ const kCount = Symbol ( 'count' ) ;
57
+ const kMaxCount = Symbol ( 'max-count' ) ;
58
+ const kDefaultMaxCount = 150 ;
56
59
57
60
observerCounts [ NODE_PERFORMANCE_ENTRY_TYPE_MARK ] = 1 ;
58
61
observerCounts [ NODE_PERFORMANCE_ENTRY_TYPE_MEASURE ] = 1 ;
@@ -250,20 +253,32 @@ const nodeTiming = new PerformanceNodeTiming();
250
253
// Maintains a list of entries as a linked list stored in insertion order.
251
254
class PerformanceObserverEntryList {
252
255
constructor ( ) {
253
- Object . defineProperty ( this , kEntries , {
254
- writable : true ,
255
- enumerable : false ,
256
- value : { }
256
+ Object . defineProperties ( this , {
257
+ [ kEntries ] : {
258
+ writable : true ,
259
+ enumerable : false ,
260
+ value : { }
261
+ } ,
262
+ [ kCount ] : {
263
+ writable : true ,
264
+ enumerable : false ,
265
+ value : 0
266
+ }
257
267
} ) ;
258
268
L . init ( this [ kEntries ] ) ;
259
269
}
260
270
261
271
[ kInsertEntry ] ( entry ) {
262
272
const item = { entry } ;
263
273
L . append ( this [ kEntries ] , item ) ;
274
+ this [ kCount ] ++ ;
264
275
this [ kIndexEntry ] ( item ) ;
265
276
}
266
277
278
+ get length ( ) {
279
+ return this [ kCount ] ;
280
+ }
281
+
267
282
[ kIndexEntry ] ( entry ) {
268
283
// Default implementation does nothing
269
284
}
@@ -384,9 +399,22 @@ class Performance extends PerformanceObserverEntryList {
384
399
this [ kIndex ] = {
385
400
[ kMarks ] : new Set ( )
386
401
} ;
402
+ this [ kMaxCount ] = kDefaultMaxCount ;
387
403
this [ kInsertEntry ] ( nodeTiming ) ;
388
404
}
389
405
406
+ set maxEntries ( val ) {
407
+ if ( typeof val !== 'number' || val >>> 0 !== val ) {
408
+ const errors = lazyErrors ( ) ;
409
+ throw new errors . TypeError ( 'ERR_INVALID_ARG_TYPE' , 'val' , 'number' ) ;
410
+ }
411
+ this [ kMaxCount ] = Math . max ( 1 , val >>> 0 ) ;
412
+ }
413
+
414
+ get maxEntries ( ) {
415
+ return this [ kMaxCount ] ;
416
+ }
417
+
390
418
[ kIndexEntry ] ( item ) {
391
419
const index = this [ kIndex ] ;
392
420
const type = item . entry . entryType ;
@@ -397,6 +425,17 @@ class Performance extends PerformanceObserverEntryList {
397
425
}
398
426
const entry = item . entry ;
399
427
L . append ( items , { entry, item } ) ;
428
+ const count = this [ kCount ] ;
429
+ if ( count > this [ kMaxCount ] ) {
430
+ const text = count === 1 ? 'is 1 entry' : `are ${ count } entries` ;
431
+ process . emitWarning ( 'Possible perf_hooks memory leak detected. ' +
432
+ `There ${ text } in the ` +
433
+ 'Performance Timeline. Use the clear methods ' +
434
+ 'to remove entries that are no longer needed or ' +
435
+ 'set performance.maxEntries equal to a higher ' +
436
+ 'value (currently the maxEntries is ' +
437
+ `${ this [ kMaxCount ] } ).` ) ;
438
+ }
400
439
}
401
440
402
441
[ kClearEntry ] ( type , name ) {
@@ -411,10 +450,12 @@ class Performance extends PerformanceObserverEntryList {
411
450
if ( entry . name === `${ name } ` ) {
412
451
L . remove ( item ) ; // remove from the index
413
452
L . remove ( item . item ) ; // remove from the master
453
+ this [ kCount ] -- ;
414
454
}
415
455
} else {
416
456
L . remove ( item ) ; // remove from the index
417
457
L . remove ( item . item ) ; // remove from the master
458
+ this [ kCount ] -- ;
418
459
}
419
460
item = next ;
420
461
}
0 commit comments