# Memory Optimization

Due to the limited memory of sports watches, third-party applications are required to have a relatively low memory footprint. Based on previous issues encountered, here is a checklist of considerations for third-party application development to help developers minimize the application's memory usage and meet the acceptance criteria for watch applications.

# Code Considerations

  1. For data unrelated to the UI that does not need to be bound, do not declare it in the viewModel's data to reduce observers or data proxies.
<template>
  <div>
    <text>{{name}}</text>     
  </div>
</template>

<script>
  const someObj = { a: 1 } // Recommended
  export default {
    protected: {
      name: 'aaa',
      someObj: { // Not recommended
        a: 1
      }
    }
  }
</script>
  1. When updating page objects, try to update them in place instead of reassigning them to avoid allocating new memory space.
export default {
  protected: {
    list: [{
      name: 'aa',
      age: 22
    }]
  },
  
  onClick() {
    // Not recommended
    this.list = [{
      name: 'bb',
      age: 21
    }]
    // Recommended
    this.list[0].name = 'bb',
    this.list[0].age = 21
  }
}
  1. Do not cache properties and methods declared in the page to the global scope.

When the page is destroyed, properties and methods related to the page object are dereferenced to clean up memory. If they are referenced globally, the memory they occupy cannot be cleaned up, and calling these cached properties and methods elsewhere may cause errors.

export default {
  protected: {
    list: [{
      name: 'aa',
      age: 22
    }]
  },
  
  onShow() {
    this.$app.$def.somearray.push(this.foo) // Not recommended
  }foo() {
    this.list.push({
      name: 'bb',
      age: 21
    })
  }
}
  1. Clear unfinished timers when the page is destroyed.
export default {
  protected: {
    timer: null
  }
  
  onShow() {
    this.timer = setTimeout(()=>{}, 1000000)
  }
  
  onDestroy() {
    if(this.timer){
      clearTimeout(this.timer)
    }
  }
}
  1. Release file data promptly after use.
let foo = await storage.getItem('key')
let bar = await file.readText('path')

let fooObj = JSON.parse(foo)
let barObj = JSON.parse(bar)

// Release promptly after use
foo = null
bar = null

fooObj = null
barObj = null
  1. Call the runGC method.

By calling the runGC method on the global global object, perform garbage collection in a timely manner to avoid memory leaks. Do not call it frequently to prevent page stuttering.

global.runGC()
  1. static property.

The template supports the static property. If the bound variable will not change later, adding the static marker helps the framework reduce dynamic nodes, thereby reducing memory usage and the time taken to delete objects when the page is destroyed.

<template>
  <div>
    <text static >{{name}}</text>
    <image static src="/assets/icon/a.png"/>   
  </div>
</template>

<script>
  export default {
    protected: {
      name: 'aaa'
    }
  }
</script>

Additionally, the .static modifier is supported on the template to mark a static attribute of a node. This is applicable when the attribute value of a node is assigned only once during initialization and does not change afterward. Usage syntax: attr.static="{{ attrValue }}"

Note

  • The if / for static attributes of nodes can only be modified using the .static modifier.
  • The static attribute of nodes has higher priority than .static. For nodes declared with the static attribute, there is no need to additionally declare the static modifier attr.static for a specific attribute.
<template>
  <div>
    <div if.static="{{ bool }}">
      <text style="{{ styl }}" someattr="{{ some }}" class="{{ cls }}" static>{{name}}</text>

      <input style="{{ styl }}" name="{{ some }}" class="{{ cls }}" value="{{ name }}" static />
    </div>

    <text
      if.static="{{ bool }}"
      style.static="{{ styl }}"
      someattr.static="{{ some }}"
      class.static="{{ cls }}"
      value.static
    >{{name}}</text>

    <input
      if.static="{{ bool }}"
      style.static="{{ styl }}"
      someattr.static="{{ some }}"
      class.static="{{ cls }}"
      value.static="{{name}}"
    />
  </div>
</template>

<script>
  export default {
    private: {
      name: 'aaa',
      bool: true,
      cls: 'basic-text',
      some: 'someattr',
      styl: {
        backgroundColor: '#d1d1d1'
      }
    }
  }
</script>

The block component is a logical block node. If the static attribute is added, it indicates that all nodes contained within the block have static data bindings, and the bound data is calculated only once and does not change afterward. This is suitable for binding enumerated values or immutable list data, effectively reducing memory usage.

<template>
  <!-- Data within the block is calculated and rendered only once -->
  <block static>
    <text class="{{cls}}">Title: {{title}}</text>
    <text>Conditional rendering</text>
    <list>
      <list-item for="{{list}}" type="item">
        <text>{{$item}}</text>
      </list-item>
    </list>
  </block>
</template>
<script>
  export default {
    private: {
      title: 'I am title 1',
      cls: 'txt-cls',
      display: true,
      list: ['a', 'b', 'c']
    }
  }
</script>

# Reduce Package Size

  1. Reduce unnecessary third-party dependencies and choose lightweight alternatives.

For third-party dependencies in package.json, remove unused dependencies and replace necessary large dependencies with lightweight alternatives.

  1. Use global methods.

Hang common methods, constants, and object instances on the global object to avoid importing them in pages. Access them directly from global when needed.

// global.js
import foo from './foo'
import bar from './bar'

global.foo = foo
global.bar = bar

// app.ux
import './global'


// pages/xxx/index.js
const {foo, bar} = global

export default {
    // Call foo and bar
    //......
}

Taking QQ Music as an example, the following is a comparison of optimization effects before and after:

Before Optimization Replace with Lightweight Dependencies Use Global Methods
Lines of Code 21965 13156 6807
Maximum Memory 4842844 3295928 1872528
  1. Use low-resolution images while ensuring image quality.

Large images consume more memory when loaded. Resize large images to smaller dimensions and then compress them (https://tinypng.com (opens new window)) to reduce their size.

  1. Remove unused CSS and JS.

Delete or comment out unused styles in CSS and unused variables and functions in JS to streamline the code.

  1. Minimize the number of pages.

Implement the application with the fewest pages possible without affecting business requirements to reduce code size and simplify application logic.