Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/368.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 减少Angular应用程序的内存利用率_Javascript_Angular_Performance_Memory Leaks_Angular5 - Fatal编程技术网

Javascript 减少Angular应用程序的内存利用率

Javascript 减少Angular应用程序的内存利用率,javascript,angular,performance,memory-leaks,angular5,Javascript,Angular,Performance,Memory Leaks,Angular5,我创建了一个包含一个表单和一个表(Priming DataTable)的数据库 为了在初始和最终读取时获得内存利用率的显著差异,我执行了多次表单Post调用(300次),并将表导航到第20页,每页1000行,还对表中的所有列进行了5次排序,并拍摄了具有初始和最终状态的堆快照(在private/incognito选项卡中禁用所有附加组件,并且在dev env中运行angular cli应用程序) 在chrome中,堆内存大小从55MB增加到146MB(增加91MB) 在Chrome中,堆内存大小

我创建了一个包含一个表单和一个表(Priming DataTable)的数据库

为了在初始和最终读取时获得内存利用率的显著差异,我执行了多次表单Post调用(300次),并将表导航到第20页,每页1000行,还对表中的所有列进行了5次排序,并拍摄了具有初始和最终状态的堆快照(在private/incognito选项卡中禁用所有附加组件,并且在dev env中运行angular cli应用程序)

在chrome中,堆内存大小从55MB增加到146MB(增加91MB)

在Chrome中,堆内存大小从23.16 MB增加到137.1 MB(增加113.95 MB)

当我的组件销毁时,我将取消订阅所有订阅(这将没有任何影响,因为这是一个单一组件),并且我已将changeDetectionStrategy设置为onPush

app.component.html:

<div [ngBusy]="{busy: busy, message: 'Loading data, this may take few minutes!'}"></div>
<div style="width:50%">
  <form [formGroup]="taskForm" (ngSubmit)="addTask(taskForm.value)">
    <div class="width:100%;float:left; clear:both;">
      <div style="width:20%;float:left">
        <input type="text" [formControl]="index" class="form-control" placeholder="index" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="name" class="form-control" placeholder="name" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="userId" class="form-control" placeholder="userId" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="mobile" class="form-control" placeholder="mobile" />
      </div>
      <div style="width:20%;float:left">
        <input type="date" [formControl]="taskDate" class="form-control" placeholder="taskDate" />
      </div>
    </div>
    <div class="width:100%;float:left; clear:both;">
      <button type="submit" class="btn btn-success">Add Task</button>{{taskPostCount}}
    </div>
  </form>
  <code *ngIf="addTaskResponse">{{addTaskResponse | json}}</code>
</div>

<div style="text-align:center">
  <p-dataTable [dataKey]="'_id'" *ngIf="isTableVisible()" [value]="table" expandableRows="true" (onFilter)="onColumnFilterChanged($event)"
    (onSort)="onTableColumnSortChanged($event)" [lazy]="true">
    <p-column field="index" header="Index" [filter]="true" [sortable]="true"></p-column>
    <p-column field="name" header="Task Name" [filter]="true" [sortable]="true"></p-column>
    <p-column field="mobile" header="Mobile" [filter]="true" [sortable]="true"></p-column>
    <p-column field="taskDate" header="Task Date"></p-column>
    <p-column field="createdAt" header="Date Created"></p-column>
    <p-column field="updatedAt" header="Date Updated"></p-column>
  </p-dataTable>
  <p-paginator [rowsPerPageOptions]="[10,20,30,50,100,200,300,400,500,1000]" [first]="tableSearchConfig.firstRowIndex" [totalRecords]="tableSearchConfig.totalRecords"
    *ngIf="isTableVisible()" [rows]="tableSearchConfig.rowsPerPage" (onPageChange)="onPageChanged($event)"></p-paginator>
</div>
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [AppService, TimeFromNow],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  // Properties declarations
  private unsubscribe: Subject<boolean> = new Subject<boolean>();

  constructor(private appService: AppService, private timeFromNow: TimeFromNow, private ref: ChangeDetectorRef, fb: FormBuilder) {
    this.taskForm = fb.group({
      'index': ['', Validators.compose([])],
      'name': ['', Validators.compose([])],
      'userId': ['', Validators.compose([])],
      'mobile': ['', Validators.compose([])],
      'taskDate': ['', Validators.compose([])],
    });
    this.index = this.taskForm.controls['index'];
    this.name = this.taskForm.controls['name'];
    this.userId = this.taskForm.controls['userId'];
    this.mobile = this.taskForm.controls['mobile'];
    this.taskDate = this.taskForm.controls['taskDate'];
    this.setTableSearchConfig();
  }

  ngOnInit() {
    this.addBulkTasksOnLoad();
  }

  ngOnDestroy() {
    this.unsubscribe.next(true);
    this.unsubscribe.complete();
    this.unsubscribe.unsubscribe();
  }

  addBulkTasksOnLoad() {
    this.busy = this.appService.addTaskOnLoad().subscribe((res: any) => {
      this.loadTable();
    }, (err: any) => {
    });
  }

  addTask(taskForm: any) {
    this.taskPostCount++;
    this.appService.addTask(taskForm).takeUntil(this.unsubscribe).subscribe((res: any) => {
      this.addTaskResponse = res;
    },
      err => {
        this.addTaskResponse = err;
      });
  }

  loadTable(paginateEvent?: PaginateEvent, sortEvent?: SortEvent, filterEvent?: FilterEvent) {
    this.appService.getTable(this.tableSearchConfig).takeUntil(this.unsubscribe).subscribe((res: any) => {
      for (const history of res.data) {
        history.updatedAt = this.timeFromNow.transform(history.updatedAt);
      }
      this.table = res.data;
      this.setTableSearchConfig(paginateEvent, sortEvent, filterEvent, this.tableSearchConfig.pageNumberToRequest, res.totalRecords);
      this.ref.detectChanges();
    });
  }

  .
  .
  .
  .
}

添加任务{{taskPostCount}}
{{addTaskResponse | json}}
app.component.ts:

<div [ngBusy]="{busy: busy, message: 'Loading data, this may take few minutes!'}"></div>
<div style="width:50%">
  <form [formGroup]="taskForm" (ngSubmit)="addTask(taskForm.value)">
    <div class="width:100%;float:left; clear:both;">
      <div style="width:20%;float:left">
        <input type="text" [formControl]="index" class="form-control" placeholder="index" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="name" class="form-control" placeholder="name" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="userId" class="form-control" placeholder="userId" />
      </div>
      <div style="width:20%;float:left">
        <input type="text" [formControl]="mobile" class="form-control" placeholder="mobile" />
      </div>
      <div style="width:20%;float:left">
        <input type="date" [formControl]="taskDate" class="form-control" placeholder="taskDate" />
      </div>
    </div>
    <div class="width:100%;float:left; clear:both;">
      <button type="submit" class="btn btn-success">Add Task</button>{{taskPostCount}}
    </div>
  </form>
  <code *ngIf="addTaskResponse">{{addTaskResponse | json}}</code>
</div>

<div style="text-align:center">
  <p-dataTable [dataKey]="'_id'" *ngIf="isTableVisible()" [value]="table" expandableRows="true" (onFilter)="onColumnFilterChanged($event)"
    (onSort)="onTableColumnSortChanged($event)" [lazy]="true">
    <p-column field="index" header="Index" [filter]="true" [sortable]="true"></p-column>
    <p-column field="name" header="Task Name" [filter]="true" [sortable]="true"></p-column>
    <p-column field="mobile" header="Mobile" [filter]="true" [sortable]="true"></p-column>
    <p-column field="taskDate" header="Task Date"></p-column>
    <p-column field="createdAt" header="Date Created"></p-column>
    <p-column field="updatedAt" header="Date Updated"></p-column>
  </p-dataTable>
  <p-paginator [rowsPerPageOptions]="[10,20,30,50,100,200,300,400,500,1000]" [first]="tableSearchConfig.firstRowIndex" [totalRecords]="tableSearchConfig.totalRecords"
    *ngIf="isTableVisible()" [rows]="tableSearchConfig.rowsPerPage" (onPageChange)="onPageChanged($event)"></p-paginator>
</div>
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [AppService, TimeFromNow],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  // Properties declarations
  private unsubscribe: Subject<boolean> = new Subject<boolean>();

  constructor(private appService: AppService, private timeFromNow: TimeFromNow, private ref: ChangeDetectorRef, fb: FormBuilder) {
    this.taskForm = fb.group({
      'index': ['', Validators.compose([])],
      'name': ['', Validators.compose([])],
      'userId': ['', Validators.compose([])],
      'mobile': ['', Validators.compose([])],
      'taskDate': ['', Validators.compose([])],
    });
    this.index = this.taskForm.controls['index'];
    this.name = this.taskForm.controls['name'];
    this.userId = this.taskForm.controls['userId'];
    this.mobile = this.taskForm.controls['mobile'];
    this.taskDate = this.taskForm.controls['taskDate'];
    this.setTableSearchConfig();
  }

  ngOnInit() {
    this.addBulkTasksOnLoad();
  }

  ngOnDestroy() {
    this.unsubscribe.next(true);
    this.unsubscribe.complete();
    this.unsubscribe.unsubscribe();
  }

  addBulkTasksOnLoad() {
    this.busy = this.appService.addTaskOnLoad().subscribe((res: any) => {
      this.loadTable();
    }, (err: any) => {
    });
  }

  addTask(taskForm: any) {
    this.taskPostCount++;
    this.appService.addTask(taskForm).takeUntil(this.unsubscribe).subscribe((res: any) => {
      this.addTaskResponse = res;
    },
      err => {
        this.addTaskResponse = err;
      });
  }

  loadTable(paginateEvent?: PaginateEvent, sortEvent?: SortEvent, filterEvent?: FilterEvent) {
    this.appService.getTable(this.tableSearchConfig).takeUntil(this.unsubscribe).subscribe((res: any) => {
      for (const history of res.data) {
        history.updatedAt = this.timeFromNow.transform(history.updatedAt);
      }
      this.table = res.data;
      this.setTableSearchConfig(paginateEvent, sortEvent, filterEvent, this.tableSearchConfig.pageNumberToRequest, res.totalRecords);
      this.ref.detectChanges();
    });
  }

  .
  .
  .
  .
}
@组件({
选择器:'应用程序根',
templateUrl:“./app.component.html”,
样式URL:['./app.component.css'],
提供者:[AppService,TimeFromNow],
changeDetection:ChangeDetectionStrategy.OnPush
})
导出类AppComponent{
//属性声明
私人退订:主题=新主题();
构造函数(私有appService:appService,私有timeFromNow:timeFromNow,私有ref:ChangeDetectorRef,fb:FormBuilder){
this.taskForm=fb.group({
“索引”:['',验证程序。组合([])],
“名称”:['',验证程序。组合([])],
'userId':['',Validators.compose([])],
“mobile”:[“”,Validators.compose([])],
“taskDate”:[“”,Validators.compose([])],
});
this.index=this.taskForm.controls['index'];
this.name=this.taskForm.controls['name'];
this.userId=this.taskForm.controls['userId'];
this.mobile=this.taskForm.controls['mobile'];
this.taskDate=this.taskForm.controls['taskDate'];
this.setTableSearchConfig();
}
恩戈尼尼特(){
这个.addBulkTasksOnLoad();
}
恩贡德斯特罗(){
this.unsubscribe.next(true);
此为.unsubscribe.complete();
this.unsubscribe.unsubscribe();
}
addBulkTasksOnLoad(){
this.busy=this.appService.addTaskOnLoad().subscribe((res:any)=>{
这个.loadTable();
},(错误:任何)=>{
});
}
addTask(taskForm:any){
这个.taskPostCount++;
this.appService.addTask(taskForm).takeUntil(this.unsubscribe).subscribe((res:any)=>{
this.addTaskResponse=res;
},
错误=>{
this.addTaskResponse=err;
});
}
加载表(分页事件?:分页事件,分拣事件?:分拣事件,过滤事件?:过滤事件){
this.appService.getTable(this.tableSearchConfig).takeUntil(this.unsubscribe).subscribe((res:any)=>{
for(资源数据的常量历史){
history.updatedAt=this.timeFromNow.transform(history.updatedAt);
}
此表=分辨率数据;
this.setTableSearchConfig(paginateEvent、sortEvent、filterEvent、this.tableSearchConfig.pageNumberToRequest、res.totalRecords);
此.ref.detectChanges();
});
}
.
.
.
.
}

这是内存泄漏的情况吗?如果是,我到底做错了什么,或者在大量使用应用程序后内存增加是正常行为?应用程序的帧速率在最后也显著下降。

这肯定是内存泄漏,但应用程序需要详细分析,以找出导致此问题的原因。对于您的在这种情况下,我们可以看到堆大小增加,但为了知道到底是什么导致了泄漏或泄漏在哪里……您需要扩展标识符,并查看哪些对象仍保留在内存中(引用了作为应用程序的父节点)这将帮助您追踪导致这些内存泄漏的代码片段(dom或JS)

有很多好的实践可以防止你的应用程序泄露那么多信息……你可以从中找到一些(这是针对angularjs的,但同样的概念也适用)

我还发现,在一个单独的状态包装器(如ngrx/store)中隔离状态是很有用的,这样您就可以确保它不是您正在提示的数据的大小,因为使用状态,您可以清楚地看到状态对象的大小,以及清楚地、明确地改变(不是字面上的)或向状态对象添加内容

此外,变更策略不会对其产生太大影响(如果它确实对其产生影响的话)内存堆的大小,但只是有助于在内存堆中保存程序,以查看应用程序模型是否已更改,从而影响DOM中的更改。但它保持内存堆不变。因此,它与清除泄漏无关

展开每个标识符以查找哪些DOM节点已分离且仍保留在堆中!然后您可以设计如何针对泄漏进行设计…例如使用ngIf或任何其他角度指令调用它们所连接的组件上的onDestroy(垃圾收集DOM节点或对象)